@agimon-ai/po-computer-use 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/apiContracts.cjs +242 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +237 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/extensionService-Bp0q295i.cjs +504 -0
- package/dist/extensionService-Bp0q295i.cjs.map +1 -0
- package/dist/extensionService-DXvF7esO.mjs +434 -0
- package/dist/extensionService-DXvF7esO.mjs.map +1 -0
- package/dist/extensions/mcp-ui.mjs +47 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +66 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +61 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/server.cjs +1394 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +1388 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +771 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +140 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +325 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +129 -0
- package/dist/index.mjs.map +1 -0
- package/docs/computer-scripts.md +72 -0
- package/llms.txt +12 -0
- package/package.json +147 -0
- package/src/prompts/po-use-computer-use/SKILL.md +34 -0
- package/src/types/computerUse.ts +132 -0
- package/src/types/computerUseApi.ts +83 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { o as COMPUTER_USE_GUIDANCE, r as ComputerScriptRunner, s as COMPUTER_USE_TOOL_NAMES, t as DefaultComputerUseExtensionService } from "./extensionService-DXvF7esO.mjs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadDoomConfig } from "@agimon-ai/po-config";
|
|
4
|
+
//#region src/services/sessionApiClient/index.ts
|
|
5
|
+
/** Uses the injected host-owned service. Absence never triggers transport or credential discovery. */
|
|
6
|
+
function createComputerUseSessionClient(host) {
|
|
7
|
+
return host;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/services/dependencies/index.ts
|
|
11
|
+
const COMPUTER_USE_SCRIPT_PATHS_ENV = "PO_COMPUTER_USE_SCRIPT_PATHS";
|
|
12
|
+
function createComputerUseDependencies(overrides = {}) {
|
|
13
|
+
const client = overrides.client ?? createComputerUseSessionClient();
|
|
14
|
+
const allowedScriptPaths = (process.env["PO_COMPUTER_USE_SCRIPT_PATHS"] ?? "").split(path.delimiter).filter((entry) => entry.length > 0);
|
|
15
|
+
return {
|
|
16
|
+
service: overrides.service ?? new DefaultComputerUseExtensionService(client),
|
|
17
|
+
enabled: overrides.enabled ?? ((cwd) => loadDoomConfig(cwd ?? process.env.PI_PROJECT_ROOT ?? process.cwd()).computerUse?.enabled === true),
|
|
18
|
+
...client === void 0 ? {} : { client },
|
|
19
|
+
...overrides.scriptRunner !== void 0 ? { scriptRunner: overrides.scriptRunner } : client === void 0 ? {} : { scriptRunner: new ComputerScriptRunner({
|
|
20
|
+
client,
|
|
21
|
+
allowedScriptPaths
|
|
22
|
+
}) }
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/models/computerUseState.ts
|
|
27
|
+
function requireRequest(state, requestId) {
|
|
28
|
+
if (state.requestId !== requestId) throw new Error("The computer-use activation request is stale.");
|
|
29
|
+
}
|
|
30
|
+
function next(state, patch) {
|
|
31
|
+
return {
|
|
32
|
+
revision: state.revision + 1,
|
|
33
|
+
identity: state.identity,
|
|
34
|
+
...patch
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function initialComputerUseState(identity) {
|
|
38
|
+
return {
|
|
39
|
+
revision: 0,
|
|
40
|
+
phase: "inactive",
|
|
41
|
+
identity
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function reduceComputerUseState(state, event) {
|
|
45
|
+
if (event.type === "fail") return next(state, {
|
|
46
|
+
phase: "failed",
|
|
47
|
+
failure: {
|
|
48
|
+
code: event.code,
|
|
49
|
+
message: event.message
|
|
50
|
+
},
|
|
51
|
+
...state.requestId === void 0 ? {} : { requestId: state.requestId },
|
|
52
|
+
...state.target === void 0 ? {} : { target: state.target },
|
|
53
|
+
...state.grant === void 0 ? {} : { grant: state.grant }
|
|
54
|
+
});
|
|
55
|
+
if (event.type === "reset") {
|
|
56
|
+
if (state.phase !== "failed") throw new Error("Only a failed computer-use state can be reset.");
|
|
57
|
+
return next(state, { phase: "inactive" });
|
|
58
|
+
}
|
|
59
|
+
switch (state.phase) {
|
|
60
|
+
case "inactive":
|
|
61
|
+
if (event.type !== "request") throw new Error("Computer use is inactive.");
|
|
62
|
+
return next(state, {
|
|
63
|
+
phase: "requesting",
|
|
64
|
+
requestId: event.requestId,
|
|
65
|
+
target: event.target
|
|
66
|
+
});
|
|
67
|
+
case "requesting":
|
|
68
|
+
if (event.type !== "await_confirmation") throw new Error("Computer use is preparing an activation request.");
|
|
69
|
+
requireRequest(state, event.requestId);
|
|
70
|
+
return next(state, {
|
|
71
|
+
phase: "awaiting_confirmation",
|
|
72
|
+
requestId: event.requestId,
|
|
73
|
+
target: state.target
|
|
74
|
+
});
|
|
75
|
+
case "awaiting_confirmation":
|
|
76
|
+
if (event.type === "deny") {
|
|
77
|
+
requireRequest(state, event.requestId);
|
|
78
|
+
return next(state, { phase: "inactive" });
|
|
79
|
+
}
|
|
80
|
+
if (event.type !== "confirm") throw new Error("Computer use is waiting for confirmation.");
|
|
81
|
+
requireRequest(state, event.requestId);
|
|
82
|
+
return next(state, {
|
|
83
|
+
phase: "activating",
|
|
84
|
+
requestId: event.requestId,
|
|
85
|
+
target: state.target
|
|
86
|
+
});
|
|
87
|
+
case "activating":
|
|
88
|
+
if (event.type !== "activated") throw new Error("Computer use is activating.");
|
|
89
|
+
requireRequest(state, event.requestId);
|
|
90
|
+
return next(state, {
|
|
91
|
+
phase: "active",
|
|
92
|
+
requestId: event.requestId,
|
|
93
|
+
target: state.target,
|
|
94
|
+
grant: event.grant
|
|
95
|
+
});
|
|
96
|
+
case "active":
|
|
97
|
+
if (event.type !== "stop") throw new Error("Computer use is active.");
|
|
98
|
+
return next(state, {
|
|
99
|
+
phase: "stopping",
|
|
100
|
+
requestId: state.requestId,
|
|
101
|
+
target: state.target,
|
|
102
|
+
grant: state.grant
|
|
103
|
+
});
|
|
104
|
+
case "stopping":
|
|
105
|
+
if (event.type !== "stopped") throw new Error("Computer use is stopping.");
|
|
106
|
+
return next(state, { phase: "inactive" });
|
|
107
|
+
case "failed": throw new Error("Computer use must be reset before another transition.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/services/traceRedaction/index.ts
|
|
112
|
+
function redactComputerUseTrace(input) {
|
|
113
|
+
return {
|
|
114
|
+
sequence: input.sequence,
|
|
115
|
+
timestamp: input.timestamp,
|
|
116
|
+
runId: input.runId,
|
|
117
|
+
bundleId: input.bundleId,
|
|
118
|
+
actionKind: input.action.kind,
|
|
119
|
+
...input.role === void 0 ? {} : { role: input.role },
|
|
120
|
+
...input.action.kind === "set_value" ? { textLength: input.action.value.length } : {},
|
|
121
|
+
durationMs: input.durationMs,
|
|
122
|
+
outcome: input.outcome,
|
|
123
|
+
...input.errorCode === void 0 ? {} : { errorCode: input.errorCode }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { COMPUTER_USE_GUIDANCE, COMPUTER_USE_SCRIPT_PATHS_ENV, COMPUTER_USE_TOOL_NAMES, ComputerScriptRunner, DefaultComputerUseExtensionService, createComputerUseDependencies, createComputerUseSessionClient, initialComputerUseState, redactComputerUseTrace, reduceComputerUseState };
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/services/sessionApiClient/index.ts","../src/services/dependencies/index.ts","../src/models/computerUseState.ts","../src/services/traceRedaction/index.ts"],"sourcesContent":["import type { ComputerUseSessionClient } from '../../types/computerUse';\n\nexport type { ComputerUseSessionClient } from '../../types/computerUse';\n\n/** Uses the injected host-owned service. Absence never triggers transport or credential discovery. */\nexport function createComputerUseSessionClient(host?: ComputerUseSessionClient): ComputerUseSessionClient | undefined {\n return host;\n}\n","import path from 'node:path';\n\nimport { loadDoomConfig } from '@agimon-ai/po-config';\n\nimport type { ComputerUseExtensionDependencies } from '../../types/extension';\nimport { ComputerScriptRunner } from '../computerScriptRunner';\nimport { DefaultComputerUseExtensionService } from '../extensionService';\nimport { createComputerUseSessionClient } from '../sessionApiClient';\n\nexport const COMPUTER_USE_SCRIPT_PATHS_ENV = 'PO_COMPUTER_USE_SCRIPT_PATHS';\nexport function createComputerUseDependencies(\n overrides: Partial<ComputerUseExtensionDependencies> = {},\n): ComputerUseExtensionDependencies {\n const client = overrides.client ?? createComputerUseSessionClient();\n const allowedScriptPaths = (process.env[COMPUTER_USE_SCRIPT_PATHS_ENV] ?? '')\n .split(path.delimiter)\n .filter((entry) => entry.length > 0);\n return {\n service: overrides.service ?? new DefaultComputerUseExtensionService(client),\n enabled:\n overrides.enabled ??\n ((cwd) => loadDoomConfig(cwd ?? process.env.PI_PROJECT_ROOT ?? process.cwd()).computerUse?.enabled === true),\n ...(client === undefined ? {} : { client }),\n ...(overrides.scriptRunner !== undefined\n ? { scriptRunner: overrides.scriptRunner }\n : client === undefined\n ? {}\n : { scriptRunner: new ComputerScriptRunner({ client, allowedScriptPaths }) }),\n };\n}\n","import type { ComputerUseState, ComputerUseStateEvent } from '../types/computerUse';\n\nfunction requireRequest(state: ComputerUseState, requestId: string): void {\n if (state.requestId !== requestId) throw new Error('The computer-use activation request is stale.');\n}\n\nfunction next(state: ComputerUseState, patch: Omit<ComputerUseState, 'revision' | 'identity'>): ComputerUseState {\n return {\n revision: state.revision + 1,\n identity: state.identity,\n ...patch,\n };\n}\n\nexport function initialComputerUseState(identity: ComputerUseState['identity']): ComputerUseState {\n return { revision: 0, phase: 'inactive', identity };\n}\n\nexport function reduceComputerUseState(state: ComputerUseState, event: ComputerUseStateEvent): ComputerUseState {\n if (event.type === 'fail') {\n return next(state, {\n phase: 'failed',\n failure: { code: event.code, message: event.message },\n ...(state.requestId === undefined ? {} : { requestId: state.requestId }),\n ...(state.target === undefined ? {} : { target: state.target }),\n ...(state.grant === undefined ? {} : { grant: state.grant }),\n });\n }\n\n if (event.type === 'reset') {\n if (state.phase !== 'failed') throw new Error('Only a failed computer-use state can be reset.');\n return next(state, { phase: 'inactive' });\n }\n\n switch (state.phase) {\n case 'inactive': {\n if (event.type !== 'request') throw new Error('Computer use is inactive.');\n return next(state, {\n phase: 'requesting',\n requestId: event.requestId,\n target: event.target,\n });\n }\n case 'requesting': {\n if (event.type !== 'await_confirmation') throw new Error('Computer use is preparing an activation request.');\n requireRequest(state, event.requestId);\n return next(state, {\n phase: 'awaiting_confirmation',\n requestId: event.requestId,\n target: state.target,\n });\n }\n case 'awaiting_confirmation': {\n if (event.type === 'deny') {\n requireRequest(state, event.requestId);\n return next(state, { phase: 'inactive' });\n }\n if (event.type !== 'confirm') throw new Error('Computer use is waiting for confirmation.');\n requireRequest(state, event.requestId);\n return next(state, {\n phase: 'activating',\n requestId: event.requestId,\n target: state.target,\n });\n }\n case 'activating': {\n if (event.type !== 'activated') throw new Error('Computer use is activating.');\n requireRequest(state, event.requestId);\n return next(state, {\n phase: 'active',\n requestId: event.requestId,\n target: state.target,\n grant: event.grant,\n });\n }\n case 'active': {\n if (event.type !== 'stop') throw new Error('Computer use is active.');\n return next(state, {\n phase: 'stopping',\n requestId: state.requestId,\n target: state.target,\n grant: state.grant,\n });\n }\n case 'stopping': {\n if (event.type !== 'stopped') throw new Error('Computer use is stopping.');\n return next(state, { phase: 'inactive' });\n }\n case 'failed':\n throw new Error('Computer use must be reset before another transition.');\n }\n}\n","import type { ComputerUseAction, ComputerUseFailureCode } from '../../types/computerUse';\n\nexport interface ComputerUseTraceInput {\n readonly sequence: number;\n readonly timestamp: number;\n readonly runId: string;\n readonly bundleId: string;\n readonly action: ComputerUseAction;\n readonly role?: string;\n readonly durationMs: number;\n readonly outcome: 'succeeded' | 'failed' | 'uncertain';\n readonly errorCode?: ComputerUseFailureCode;\n}\n\nexport interface ComputerUseTraceRecord {\n readonly sequence: number;\n readonly timestamp: number;\n readonly runId: string;\n readonly bundleId: string;\n readonly actionKind: ComputerUseAction['kind'];\n readonly role?: string;\n readonly textLength?: number;\n readonly durationMs: number;\n readonly outcome: ComputerUseTraceInput['outcome'];\n readonly errorCode?: ComputerUseFailureCode;\n}\n\nexport function redactComputerUseTrace(input: ComputerUseTraceInput): ComputerUseTraceRecord {\n return {\n sequence: input.sequence,\n timestamp: input.timestamp,\n runId: input.runId,\n bundleId: input.bundleId,\n actionKind: input.action.kind,\n ...(input.role === undefined ? {} : { role: input.role }),\n ...(input.action.kind === 'set_value' ? { textLength: input.action.value.length } : {}),\n durationMs: input.durationMs,\n outcome: input.outcome,\n ...(input.errorCode === undefined ? {} : { errorCode: input.errorCode }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Author computer functions
|
|
2
|
+
|
|
3
|
+
`computer_exec` runs an ordinary `run` function against the application authorized by the current Desktop grant. Write the function and any helpers using the existing file tools, then call `computer_exec` with `scriptPath` and JSON `input`. A function does not need its own extension package or registered agent tool.
|
|
4
|
+
|
|
5
|
+
## Restricted execution, the default
|
|
6
|
+
|
|
7
|
+
The Desktop-backed server admits scripts below the session working directory. Entry files and relative helpers may use `.ts`, `.js`, or `.mjs`. TypeScript must use erasable syntax. The loader resolves real paths and rejects helpers that escape this directory, including through symlinks. Inline source, package imports, and `node:` imports are not supported in restricted execution.
|
|
8
|
+
|
|
9
|
+
Generated code runs inside a separate QuickJS WebAssembly runtime in a child process. Only the program callbacks, JSON input, bounded logger, and portable cancellation signal are exposed. Node globals, environment variables, filesystem access, networking, subprocesses, and host constructors are not exposed to the function. Relative helpers execute with the same restrictions. This is not permission to control another application: every program operation still passes through the current session's Desktop grant checks.
|
|
10
|
+
|
|
11
|
+
## Function contract
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { ComputerScriptProgram, ComputerScriptRun } from '@agimon-ai/po-computer-use';
|
|
15
|
+
|
|
16
|
+
async function pressByLabel(program: ComputerScriptProgram, label: string) {
|
|
17
|
+
const snapshot = await program.observe();
|
|
18
|
+
const matches = snapshot.elements.filter(
|
|
19
|
+
(element) => element.label === label && element.enabled && !element.secure && element.actions.includes('press'),
|
|
20
|
+
);
|
|
21
|
+
if (matches.length !== 1) throw new Error(`Expected one pressable element named ${label}.`);
|
|
22
|
+
await program.act({
|
|
23
|
+
kind: 'press',
|
|
24
|
+
snapshotId: snapshot.snapshotId,
|
|
25
|
+
elementRef: matches[0]!.ref,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const run: ComputerScriptRun = async ({ context: { program }, input, logger, signal }) => {
|
|
30
|
+
if (typeof input !== 'object' || input === null || !('label' in input) || typeof input.label !== 'string') {
|
|
31
|
+
throw new Error('input.label must be a string.');
|
|
32
|
+
}
|
|
33
|
+
signal.throwIfAborted();
|
|
34
|
+
await pressByLabel(program, input.label);
|
|
35
|
+
logger.info('Pressed the requested element.');
|
|
36
|
+
return { pressed: input.label };
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Type-only imports are erased before execution. Runtime helpers can be moved into neighboring files and imported with explicit relative paths such as `./press.ts`.
|
|
41
|
+
|
|
42
|
+
`program.observe()` returns current semantic state without a screenshot by default. `program.observe({ includeScreenshot: true })` additionally captures an image. `program.act(action)` supports `press`, `focus`, `set_value`, and `scroll` against current snapshot IDs and element refs. Calls are serialized even when the function starts several promises. Re-observe after changes; serialization does not make old snapshots valid.
|
|
43
|
+
|
|
44
|
+
Use normal local variables and function arguments for working state within a chain. An observation is a snapshot, not a mutable application instance. Actual application changes must use `program.act`. Each invocation starts a fresh worker; module globals do not persist across invocations.
|
|
45
|
+
|
|
46
|
+
The portable `signal` supports `aborted` and `throwIfAborted()`. Restricted functions should not assume the rest of the Node AbortSignal or timer APIs exists. An external timeout can terminate synchronous infinite loops as well as pending asynchronous work.
|
|
47
|
+
|
|
48
|
+
## Tool result and limits
|
|
49
|
+
|
|
50
|
+
By default, successful `computer_exec` returns the function's JSON result, bounded logs, a fresh semantic observation, and execution metrics. Pass `includeScreenshot: true` to the tool to include a final image. Images use image content blocks, not base64 embedded in model-facing observation text. Avoid returning image data inside the function's own result.
|
|
51
|
+
|
|
52
|
+
The default execution deadline is 30 seconds. Input and text output are bounded to 256 KiB, with the final semantic observation counted against output. The final tool formatter also checks the complete text response. Images have a separate 6 MiB decoded-size ceiling. Restricted execution limits its JavaScript heap to 32 MiB, stack to 512 KiB, helper graph to 32 modules, individual source files to 256 KiB, total source to 512 KiB, and outstanding program operations to 64.
|
|
53
|
+
|
|
54
|
+
On failure, `computer_exec` reports completed actions and whether an action's outcome is uncertain when that information is available. Cancellation prevents queued actions from starting and attempts to abort the current request. An interrupted request may already have changed the application, so do not automatically retry the entire chain or repeat the uncertain action. Re-establish authorized, fresh state before continuing.
|
|
55
|
+
|
|
56
|
+
Metrics describe this invocation's action count, observation count, elapsed milliseconds, and counted text-output bytes. They are not a measurement of model tokens or native application reliability.
|
|
57
|
+
|
|
58
|
+
## Explicitly trusted Node scripts
|
|
59
|
+
|
|
60
|
+
Full Node execution remains available only with `trusted: true` and an entry path explicitly included in the host-configured `PO_COMPUTER_USE_SCRIPT_PATHS`. The value is a platform-delimited list of exact paths, not directories or globs:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
export PO_COMPUTER_USE_SCRIPT_PATHS="$PWD/scripts/reviewed.ts"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Trusted scripts use normal file-based module loading, including relative imports. They are **not sandboxed** and inherit the Pi process environment and permissions. Review the entrypoint and every dependency before allowing them, and protect those files against unreviewed modification. The path allowlist is not a content signature and does not approve subsequent edits or dependency changes. Setting an allowlisted path alone does not switch execution out of restricted mode.
|
|
67
|
+
|
|
68
|
+
## Desktop ownership
|
|
69
|
+
|
|
70
|
+
Mode selection, global opt-in, and a native application grant are separate. A selected mode is not authority. Before granting control, the owning Desktop renderer must authorize the request, and the agent must be idle with no queued prompts. The native host then asks for confirmation of the application window and duration.
|
|
71
|
+
|
|
72
|
+
Once Desktop claims a session for this workflow, browser and remote MCP clients cannot drive that session, including connections attached before the claim. The claim remains pinned for the server lifetime, even after stopping control or losing Desktop, so another client cannot take over a session that handled Desktop capabilities. Grants and claims are not restored from persisted session data.
|
package/llms.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @agimon-ai/po-computer-use
|
|
2
|
+
|
|
3
|
+
Session-scoped semantic computer control through Po Desktop.
|
|
4
|
+
|
|
5
|
+
## Guidance
|
|
6
|
+
|
|
7
|
+
- [Use Computer Use](./src/prompts/po-use-computer-use/SKILL.md): Active-mode safety, observation, action, confirmation, and shutdown guidance.
|
|
8
|
+
|
|
9
|
+
## Resources
|
|
10
|
+
|
|
11
|
+
- [Package README](./README.md): Installation, activation workflow, tools, API boundaries, and development commands.
|
|
12
|
+
- [Author computer scripts](./docs/computer-scripts.md): Trusted script authorization, runtime contract, limits, and example.
|
package/package.json
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agimon-ai/po-computer-use",
|
|
3
|
+
"version": "0.0.0-alpha.0",
|
|
4
|
+
"description": "Session scoped semantic computer control through the Po Desktop capability.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"coding-agent",
|
|
8
|
+
"computer-use",
|
|
9
|
+
"developer-tools",
|
|
10
|
+
"pi-coding-agent",
|
|
11
|
+
"pi-extension",
|
|
12
|
+
"pi-package",
|
|
13
|
+
"po",
|
|
14
|
+
"typescript"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://agimon.ai",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/AgiFlow/po/issues"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Vuong Ngo",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/AgiFlow/po.git",
|
|
25
|
+
"directory": "packages/minor/po-computer-use"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"docs",
|
|
30
|
+
"src/types/computerUse.ts",
|
|
31
|
+
"src/types/computerUseApi.ts",
|
|
32
|
+
"src/prompts",
|
|
33
|
+
"llms.txt",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"package.json"
|
|
37
|
+
],
|
|
38
|
+
"type": "module",
|
|
39
|
+
"main": "./dist/index.cjs",
|
|
40
|
+
"module": "./dist/index.mjs",
|
|
41
|
+
"types": "./dist/index.d.mts",
|
|
42
|
+
"jsnext:main": "./dist/index.mjs",
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": "./dist/index.d.mts",
|
|
46
|
+
"import": "./dist/index.mjs",
|
|
47
|
+
"require": "./dist/index.cjs"
|
|
48
|
+
},
|
|
49
|
+
"./extensions/server": {
|
|
50
|
+
"types": "./dist/extensions/server.d.mts",
|
|
51
|
+
"import": "./dist/extensions/server.mjs",
|
|
52
|
+
"require": "./dist/extensions/server.cjs"
|
|
53
|
+
},
|
|
54
|
+
"./extensions/web": {
|
|
55
|
+
"import": "./dist/extensions/web.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./package.json": "./package.json"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@agimon-ai/po-config": "0.0.0-alpha.0",
|
|
64
|
+
"@agimon-ai/po-core": "0.0.0-alpha.0",
|
|
65
|
+
"@agimon-ai/po-minor-mode": "0.0.0-alpha.0",
|
|
66
|
+
"@agimon-ai/po-web-components": "0.0.0-alpha.0",
|
|
67
|
+
"@agimon-ai/po-web-security": "0.0.0-alpha.0",
|
|
68
|
+
"@deepseek-ai/cordis": "4.0.4",
|
|
69
|
+
"quickjs-emscripten": "0.32.0",
|
|
70
|
+
"typebox": "1.3.34"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@agimon-ai/po-build": "0.0.0-alpha.0",
|
|
74
|
+
"@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.0-alpha.0",
|
|
75
|
+
"@earendil-works/pi-coding-agent": "1.0.2",
|
|
76
|
+
"@tanstack/react-store": "0.11.2",
|
|
77
|
+
"@tanstack/store": "0.11.2",
|
|
78
|
+
"@types/node": "26.6.4",
|
|
79
|
+
"@types/react": "19.3.0",
|
|
80
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
81
|
+
"react": "19.3.0",
|
|
82
|
+
"react-dom": "19.3.0",
|
|
83
|
+
"tsdown": "0.23.0",
|
|
84
|
+
"typescript": "7.0.2",
|
|
85
|
+
"vitest": "5.0.3"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"@earendil-works/pi-coding-agent": "1.0.2"
|
|
89
|
+
},
|
|
90
|
+
"peerDependenciesMeta": {
|
|
91
|
+
"@earendil-works/pi-coding-agent": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"engines": {
|
|
96
|
+
"node": ">=24"
|
|
97
|
+
},
|
|
98
|
+
"poMcp": {
|
|
99
|
+
"entry": "./generated/mcp.ts",
|
|
100
|
+
"dist": "./dist/extensions/mcp.mjs",
|
|
101
|
+
"scopes": [
|
|
102
|
+
"session"
|
|
103
|
+
],
|
|
104
|
+
"ui": {
|
|
105
|
+
"entry": "./generated/mcp-ui.ts",
|
|
106
|
+
"dist": "./dist/extensions/mcp-ui.mjs",
|
|
107
|
+
"widgets": [
|
|
108
|
+
"@agimon-ai/po-computer-use/computer_action",
|
|
109
|
+
"@agimon-ai/po-computer-use/computer_exec",
|
|
110
|
+
"@agimon-ai/po-computer-use/computer_state"
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"poServer": {
|
|
115
|
+
"entry": "./generated/server.ts",
|
|
116
|
+
"dist": "./dist/extensions/server.mjs",
|
|
117
|
+
"scopes": [
|
|
118
|
+
"global",
|
|
119
|
+
"workspace",
|
|
120
|
+
"session"
|
|
121
|
+
],
|
|
122
|
+
"contracts": {
|
|
123
|
+
"entry": "./src/exports/apiContracts.ts",
|
|
124
|
+
"dist": "./dist/apiContracts.mjs"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"poWeb": {
|
|
128
|
+
"pluginId": "computer-use",
|
|
129
|
+
"channels": [
|
|
130
|
+
"computer_use"
|
|
131
|
+
],
|
|
132
|
+
"client": "./dist/extensions/web.mjs",
|
|
133
|
+
"scopes": [
|
|
134
|
+
"global",
|
|
135
|
+
"workspace",
|
|
136
|
+
"session"
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
"scripts": {
|
|
140
|
+
"build": "tsdown && tsdown --config tsdown.mcp.config.ts",
|
|
141
|
+
"build:mcp": "tsdown --config tsdown.mcp.config.ts",
|
|
142
|
+
"test": "vitest --run",
|
|
143
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json && tsc --noEmit -p tsconfig.mcp.json",
|
|
144
|
+
"lint": "oxlint . && oxfmt . --check",
|
|
145
|
+
"fixcode": "oxlint . --fix && oxfmt ."
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: po-use-computer-use
|
|
3
|
+
description: 'Use Desktop-authorized semantic computer control and compose restricted application functions.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Use Computer Use
|
|
7
|
+
|
|
8
|
+
This guidance applies only while this session holds an active application grant from its owning Po Desktop instance. A selected minor mode is not a grant. Normal browsers and remote MCP clients cannot obtain Desktop authority.
|
|
9
|
+
|
|
10
|
+
## Observe and act
|
|
11
|
+
|
|
12
|
+
Call `computer_state` before choosing an action. Use `includeScreenshot: false` for semantic-only inspection when an image is unnecessary. Use only the snapshot IDs and element refs returned by the current observation. `computer_action` supports `press`, `focus`, `set_value`, and `scroll`. Never infer coordinates, inspect another application, or bypass secure elements.
|
|
13
|
+
|
|
14
|
+
Re-observe after actions that change the interface. Check the expected outcome rather than replaying stale refs or sleeping for a guessed interval. An observation is a snapshot: editing its fields does not mutate the application.
|
|
15
|
+
|
|
16
|
+
## Compose reusable functions
|
|
17
|
+
|
|
18
|
+
For predictable multi-step work, write a `.ts`, `.js`, or `.mjs` file below the session working directory using the existing file tools. Export `run({ context: { program }, input, logger, signal })`. Invoke it through `computer_exec` with `scriptPath` and JSON `input`. This batches local actions into one agent tool call; it does not require registering a new tool per function.
|
|
19
|
+
|
|
20
|
+
The authorized `program` exposes `observe(options?)` and `act(action)`. Keep working state in ordinary variables and pass it to helper functions. Helpers can be imported with explicit relative paths within the working directory. Re-observe inside the chain whenever a previous action may have invalidated a snapshot.
|
|
21
|
+
|
|
22
|
+
Generated functions run with restricted capabilities, not as Node programs. Do not import `node:` modules, installed packages, network APIs, or host constructors. Type-only imports are erased. Cancellation supports `signal.aborted` and `signal.throwIfAborted()`. Each invocation starts fresh; do not rely on globals persisting.
|
|
23
|
+
|
|
24
|
+
`program.observe()` and the final `computer_exec` observation omit screenshots by default. Request `includeScreenshot: true` only where an image is needed. Return compact JSON, not screenshot base64 or entire repeated observations. Keep logs small. The default deadline is 30 seconds and bounded text output includes the final semantic observation.
|
|
25
|
+
|
|
26
|
+
Full Node execution is a separate trusted path. Never request `trusted: true` to evade a restricted-runtime error. It requires an explicitly host-allowlisted entry and reviewed dependencies; those programs are not sandboxed.
|
|
27
|
+
|
|
28
|
+
## Stop and recover
|
|
29
|
+
|
|
30
|
+
Failures report completed actions and uncertain outcomes where available. Never automatically retry an uncertain action or replay a partially completed chain. Stop, inspect the failure, and re-establish authorized fresh state before continuing.
|
|
31
|
+
|
|
32
|
+
Activation requires Desktop's global opt-in, the selected mode, an idle agent without queued prompts, and explicit native confirmation of the target window and duration. Once Desktop claims the session, browser and remote MCP clients cannot drive it for the rest of the server lifetime. Grants are not restored across restarts.
|
|
33
|
+
|
|
34
|
+
Stop Computer Use when the requested task is complete. Expiry, cancellation, mode disable, global disable, and Desktop disconnection must not be bypassed.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ComputerUseSessionView } from './computerUseApi';
|
|
2
|
+
|
|
3
|
+
export interface ComputerUseSessionClient {
|
|
4
|
+
state(signal?: AbortSignal): Promise<ComputerUseSessionView>;
|
|
5
|
+
subscribeStatus?(listener: (state: ComputerUseSessionView) => void): () => void;
|
|
6
|
+
observe(signal?: AbortSignal, options?: ComputerUseObservationOptions): Promise<ComputerUseObservation>;
|
|
7
|
+
act(action: ComputerUseAction, signal?: AbortSignal): Promise<unknown>;
|
|
8
|
+
stop(signal?: AbortSignal): Promise<ComputerUseSessionView>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ComputerUseObservationOptions {
|
|
12
|
+
includeScreenshot?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const COMPUTER_USE_PHASES = [
|
|
16
|
+
'inactive',
|
|
17
|
+
'requesting',
|
|
18
|
+
'awaiting_confirmation',
|
|
19
|
+
'activating',
|
|
20
|
+
'active',
|
|
21
|
+
'stopping',
|
|
22
|
+
'failed',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
export type ComputerUsePhase = (typeof COMPUTER_USE_PHASES)[number];
|
|
26
|
+
|
|
27
|
+
export interface ComputerUseSessionIdentity {
|
|
28
|
+
readonly sessionId: string;
|
|
29
|
+
readonly runtimeId: string;
|
|
30
|
+
readonly modeEpoch: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ComputerUseTarget {
|
|
34
|
+
readonly bundleId: string;
|
|
35
|
+
readonly applicationName: string;
|
|
36
|
+
readonly processId: number;
|
|
37
|
+
readonly windowId: string;
|
|
38
|
+
readonly windowTitle: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ComputerUseGrant {
|
|
42
|
+
readonly runId: string;
|
|
43
|
+
readonly grantId: string;
|
|
44
|
+
readonly hostGeneration: string;
|
|
45
|
+
readonly targetGeneration: string;
|
|
46
|
+
readonly expiresAt: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ComputerUseElement {
|
|
50
|
+
readonly ref: string;
|
|
51
|
+
readonly role: string;
|
|
52
|
+
readonly label?: string;
|
|
53
|
+
readonly value?: string;
|
|
54
|
+
readonly enabled: boolean;
|
|
55
|
+
readonly secure: boolean;
|
|
56
|
+
readonly actions: readonly ComputerUseActionKind[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ComputerUseObservation {
|
|
60
|
+
readonly runId: string;
|
|
61
|
+
readonly snapshotId: string;
|
|
62
|
+
readonly targetGeneration: string;
|
|
63
|
+
readonly applicationName: string;
|
|
64
|
+
readonly bundleId: string;
|
|
65
|
+
readonly windowTitle: string;
|
|
66
|
+
readonly elements: readonly ComputerUseElement[];
|
|
67
|
+
readonly screenshot?: {
|
|
68
|
+
readonly mimeType: 'image/png';
|
|
69
|
+
readonly data: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type ComputerUseActionKind = 'press' | 'focus' | 'set_value' | 'scroll';
|
|
74
|
+
|
|
75
|
+
export type ComputerUseAction =
|
|
76
|
+
| {
|
|
77
|
+
readonly kind: 'press' | 'focus';
|
|
78
|
+
readonly snapshotId: string;
|
|
79
|
+
readonly elementRef: string;
|
|
80
|
+
}
|
|
81
|
+
| {
|
|
82
|
+
readonly kind: 'set_value';
|
|
83
|
+
readonly snapshotId: string;
|
|
84
|
+
readonly elementRef: string;
|
|
85
|
+
readonly value: string;
|
|
86
|
+
}
|
|
87
|
+
| {
|
|
88
|
+
readonly kind: 'scroll';
|
|
89
|
+
readonly snapshotId: string;
|
|
90
|
+
readonly elementRef: string;
|
|
91
|
+
readonly direction: 'up' | 'down' | 'left' | 'right';
|
|
92
|
+
readonly amount: 'line' | 'page';
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type ComputerUseFailureCode =
|
|
96
|
+
| 'busy_in_another_session'
|
|
97
|
+
| 'desktop_unavailable'
|
|
98
|
+
| 'permission_required_on_mac'
|
|
99
|
+
| 'confirmation_denied'
|
|
100
|
+
| 'confirmation_expired'
|
|
101
|
+
| 'target_invalid'
|
|
102
|
+
| 'target_lost'
|
|
103
|
+
| 'recording_failed'
|
|
104
|
+
| 'trace_failed'
|
|
105
|
+
| 'grant_expired'
|
|
106
|
+
| 'stale_request'
|
|
107
|
+
| 'outcome_uncertain'
|
|
108
|
+
| 'internal_error';
|
|
109
|
+
|
|
110
|
+
export interface ComputerUseState {
|
|
111
|
+
readonly revision: number;
|
|
112
|
+
readonly phase: ComputerUsePhase;
|
|
113
|
+
readonly identity: ComputerUseSessionIdentity;
|
|
114
|
+
readonly requestId?: string;
|
|
115
|
+
readonly target?: ComputerUseTarget;
|
|
116
|
+
readonly grant?: ComputerUseGrant;
|
|
117
|
+
readonly failure?: {
|
|
118
|
+
readonly code: ComputerUseFailureCode;
|
|
119
|
+
readonly message: string;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type ComputerUseStateEvent =
|
|
124
|
+
| { readonly type: 'request'; readonly requestId: string; readonly target: ComputerUseTarget }
|
|
125
|
+
| { readonly type: 'await_confirmation'; readonly requestId: string }
|
|
126
|
+
| { readonly type: 'confirm'; readonly requestId: string }
|
|
127
|
+
| { readonly type: 'deny'; readonly requestId: string }
|
|
128
|
+
| { readonly type: 'activated'; readonly requestId: string; readonly grant: ComputerUseGrant }
|
|
129
|
+
| { readonly type: 'stop' }
|
|
130
|
+
| { readonly type: 'stopped' }
|
|
131
|
+
| { readonly type: 'fail'; readonly code: ComputerUseFailureCode; readonly message: string }
|
|
132
|
+
| { readonly type: 'reset' };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { DoomApiCaller } from '@agimon-ai/po-core/packageApi';
|
|
2
|
+
|
|
3
|
+
export const API_BASE_PATH = 'computer-use';
|
|
4
|
+
export const computerUseChannelType = 'computer_use_state';
|
|
5
|
+
export const COMPUTER_USE_MODE_ID = 'computer-use';
|
|
6
|
+
export const COMPUTER_USE_STATUS_KEY = 'doom-computer-use';
|
|
7
|
+
export const COMPUTER_USE_MODE_STATUS_KEY = 'doom-computer-use-mode';
|
|
8
|
+
export const COMPUTER_USE_MAX_DURATION_MS = 1_800 * 1_000;
|
|
9
|
+
export const COMPUTER_USE_DEFAULT_DURATION_MS = 300 * 1_000;
|
|
10
|
+
export const COMPUTER_USE_CONFIRMATION_WINDOW_MS = 2 * 60 * 1_000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Every path this API answers on, below its mount.
|
|
14
|
+
*
|
|
15
|
+
* The typed route table in `./apiRoutes` is built from this, the dispatcher
|
|
16
|
+
* reads that table, and the hub channel addresses the broker with these same
|
|
17
|
+
* strings, so a route cannot move on one side alone.
|
|
18
|
+
*/
|
|
19
|
+
export const COMPUTER_USE_ROUTES = {
|
|
20
|
+
activate: '/activate',
|
|
21
|
+
artifact: '/artifact',
|
|
22
|
+
agentState: '/agent/state',
|
|
23
|
+
agentObserve: '/agent/observe',
|
|
24
|
+
agentAction: '/agent/action',
|
|
25
|
+
agentStop: '/agent/stop',
|
|
26
|
+
hubState: '/hub/state',
|
|
27
|
+
hubActivation: '/hub/activation',
|
|
28
|
+
hubAuthorization: '/hub/authorization',
|
|
29
|
+
hubNext: '/hub/next',
|
|
30
|
+
hubComplete: '/hub/complete',
|
|
31
|
+
hubStop: '/hub/stop',
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
export const COMPUTER_USE_WAKE_LIMIT = 1_000_000;
|
|
35
|
+
|
|
36
|
+
export interface ComputerUseArtifactView {
|
|
37
|
+
readonly artifactId: string;
|
|
38
|
+
readonly status: 'ready' | 'failed';
|
|
39
|
+
readonly sizeBytes?: number;
|
|
40
|
+
readonly downloadUrl?: string;
|
|
41
|
+
readonly previewUrl?: string;
|
|
42
|
+
readonly actionCount?: number;
|
|
43
|
+
readonly completedAt?: string;
|
|
44
|
+
readonly failure?: { readonly code: string; readonly message: string };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ComputerUseSessionView {
|
|
48
|
+
readonly sessionId: string;
|
|
49
|
+
readonly revision: number;
|
|
50
|
+
readonly wake: number;
|
|
51
|
+
readonly phase: 'inactive' | 'awaiting_confirmation' | 'activating' | 'active' | 'stopping' | 'failed';
|
|
52
|
+
readonly requestId?: string;
|
|
53
|
+
readonly target?: Record<string, unknown>;
|
|
54
|
+
readonly durationMs?: number;
|
|
55
|
+
readonly expiresAt?: number;
|
|
56
|
+
readonly failure?: { readonly code: string; readonly message: string };
|
|
57
|
+
readonly artifact?: ComputerUseArtifactView;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ComputerUseActivationRequest {
|
|
61
|
+
readonly requestId: string;
|
|
62
|
+
readonly target?: Record<string, unknown>;
|
|
63
|
+
readonly durationSeconds: number;
|
|
64
|
+
readonly createdAt: number;
|
|
65
|
+
readonly confirmationExpiresAt: number;
|
|
66
|
+
readonly caller: DoomApiCaller;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ComputerUseBrokerRequest {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
readonly operation: 'observe' | 'act';
|
|
72
|
+
readonly payload?: unknown;
|
|
73
|
+
readonly grantId: string;
|
|
74
|
+
readonly sequence?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ComputerUseChannelPayload {
|
|
78
|
+
readonly state: ComputerUseSessionView;
|
|
79
|
+
readonly targets: readonly Record<string, unknown>[];
|
|
80
|
+
readonly busy?: true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type ComputerUseBrowserCommand = { readonly action: 'status' | 'targets' | 'stop' | 'artifacts' };
|