@oharness/engine 0.9.2 → 0.10.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/dist/agent/agent.d.ts +207 -1
- package/dist/agent/agent.js +691 -55
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/background.d.ts +135 -0
- package/dist/agent/background.js +307 -0
- package/dist/agent/background.js.map +1 -0
- package/dist/agent/compaction.d.ts +7 -0
- package/dist/agent/compaction.js +11 -3
- package/dist/agent/compaction.js.map +1 -1
- package/dist/agent/goal.d.ts +36 -0
- package/dist/agent/goal.js +71 -0
- package/dist/agent/goal.js.map +1 -0
- package/dist/agent/permissions.d.ts +6 -0
- package/dist/agent/permissions.js +2 -1
- package/dist/agent/permissions.js.map +1 -1
- package/dist/agent/session.d.ts +36 -0
- package/dist/agent/session.js +72 -0
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/store.d.ts +25 -0
- package/dist/agent/store.js +21 -0
- package/dist/agent/store.js.map +1 -1
- package/dist/agent/subagent.d.ts +12 -0
- package/dist/agent/subagent.js +11 -1
- package/dist/agent/subagent.js.map +1 -1
- package/dist/agent/workspace.d.ts +9 -0
- package/dist/agent/workspace.js +59 -5
- package/dist/agent/workspace.js.map +1 -1
- package/dist/auth/manager.d.ts +9 -0
- package/dist/auth/manager.js +67 -6
- package/dist/auth/manager.js.map +1 -1
- package/dist/auth/providers/account.js +5 -4
- package/dist/auth/providers/account.js.map +1 -1
- package/dist/browser/tools.js +3 -0
- package/dist/browser/tools.js.map +1 -1
- package/dist/computer/arbiter.d.ts +69 -0
- package/dist/computer/arbiter.js +128 -0
- package/dist/computer/arbiter.js.map +1 -0
- package/dist/computer/cua-driver.d.ts +115 -0
- package/dist/computer/cua-driver.js +453 -0
- package/dist/computer/cua-driver.js.map +1 -0
- package/dist/computer/helper-client.d.ts +78 -0
- package/dist/computer/helper-client.js +163 -0
- package/dist/computer/helper-client.js.map +1 -0
- package/dist/computer/index.d.ts +15 -0
- package/dist/computer/index.js +9 -0
- package/dist/computer/index.js.map +1 -0
- package/dist/computer/mode.d.ts +19 -0
- package/dist/computer/mode.js +42 -0
- package/dist/computer/mode.js.map +1 -0
- package/dist/computer/plugin.d.ts +24 -0
- package/dist/computer/plugin.js +17 -0
- package/dist/computer/plugin.js.map +1 -0
- package/dist/computer/policy.d.ts +29 -0
- package/dist/computer/policy.js +127 -0
- package/dist/computer/policy.js.map +1 -0
- package/dist/computer/session.d.ts +199 -0
- package/dist/computer/session.js +392 -0
- package/dist/computer/session.js.map +1 -0
- package/dist/computer/target.d.ts +187 -0
- package/dist/computer/target.js +31 -0
- package/dist/computer/target.js.map +1 -0
- package/dist/computer/tools.d.ts +8 -0
- package/dist/computer/tools.js +537 -0
- package/dist/computer/tools.js.map +1 -0
- package/dist/core/tokens.js +4 -0
- package/dist/core/tokens.js.map +1 -1
- package/dist/core/types.d.ts +16 -1
- package/dist/core/types.js.map +1 -1
- package/dist/harness.d.ts +76 -1
- package/dist/harness.js +178 -22
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/transport.js +3 -0
- package/dist/mcp/transport.js.map +1 -1
- package/dist/providers/catalog.js +6 -0
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/discovery.js +10 -2
- package/dist/providers/discovery.js.map +1 -1
- package/dist/providers/models-dev.js +1 -0
- package/dist/providers/models-dev.js.map +1 -1
- package/dist/providers/models-dev.json +114 -102
- package/dist/providers/piai.d.ts +16 -1
- package/dist/providers/piai.js +84 -7
- package/dist/providers/piai.js.map +1 -1
- package/dist/providers/types.d.ts +6 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/runtime-plugins/cloud-connector.js +5 -0
- package/dist/runtime-plugins/cloud-connector.js.map +1 -1
- package/dist/schedule/scheduler.d.ts +38 -0
- package/dist/schedule/scheduler.js +101 -1
- package/dist/schedule/scheduler.js.map +1 -1
- package/dist/tools/builtin/bash.d.ts +6 -0
- package/dist/tools/builtin/bash.js +2 -1
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/recall.js +4 -0
- package/dist/tools/builtin/recall.js.map +1 -1
- package/dist/tools/builtin/routine.d.ts +9 -0
- package/dist/tools/builtin/routine.js +23 -2
- package/dist/tools/builtin/routine.js.map +1 -1
- package/dist/tools/builtin/task-control.d.ts +21 -0
- package/dist/tools/builtin/task-control.js +120 -0
- package/dist/tools/builtin/task-control.js.map +1 -0
- package/dist/tools/builtin/task.js +50 -9
- package/dist/tools/builtin/task.js.map +1 -1
- package/dist/tools/builtin/todo.d.ts +1 -1
- package/dist/tools/builtin/worktree.d.ts +10 -0
- package/dist/tools/builtin/worktree.js +52 -0
- package/dist/tools/builtin/worktree.js.map +1 -0
- package/dist/tools/define.d.ts +4 -1
- package/dist/tools/define.js +2 -0
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/types.d.ts +112 -0
- package/dist/tools/types.js.map +1 -1
- package/dist/worktree/index.d.ts +109 -0
- package/dist/worktree/index.js +463 -0
- package/dist/worktree/index.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { Logger } from "../util/logger.ts";
|
|
2
|
+
import { ComputerArbiter } from "./arbiter.ts";
|
|
3
|
+
import type { LeaseHolder } from "./arbiter.ts";
|
|
4
|
+
import type { ActionKind, ComputerTier, PolicyOptions } from "./policy.ts";
|
|
5
|
+
import type { AppInfo, AxNode, ComputerPermissions, ComputerTarget, ComputerTargetFactory, HelperInfo, Rect, Shot, WindowInfo } from "./target.ts";
|
|
6
|
+
/**
|
|
7
|
+
* What the page and the overlay are told about each action, so the person can
|
|
8
|
+
* see where the agent is working without reading the transcript. Presentation
|
|
9
|
+
* only: nothing here goes to the model.
|
|
10
|
+
*/
|
|
11
|
+
export interface ComputerActionEvent {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
label: string;
|
|
14
|
+
kind: "look" | "click" | "type" | "scroll" | "drag" | "key" | "control" | "release" | "idle";
|
|
15
|
+
window?: string;
|
|
16
|
+
app?: string;
|
|
17
|
+
/** Screen point the action lands on, when it has one. */
|
|
18
|
+
point?: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
};
|
|
22
|
+
/** Whether that point is on screen and uncovered: the overlay draws the cursor only then. */
|
|
23
|
+
visible?: boolean;
|
|
24
|
+
/** Frame of the element acted on, for a ref action. */
|
|
25
|
+
frame?: Rect;
|
|
26
|
+
/** Where the window is on screen, so a live view can place the point inside it. */
|
|
27
|
+
windowFrame?: Rect;
|
|
28
|
+
/** The window's title, for the live view's heading. */
|
|
29
|
+
title?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* What the windows a turn worked in looked like when it ended, for the person
|
|
33
|
+
* reading the conversation back. Never model input: the agent works from the
|
|
34
|
+
* accessibility tree and takes its own screenshots when it needs one.
|
|
35
|
+
*/
|
|
36
|
+
export interface ComputerSnapshotEvent {
|
|
37
|
+
sessionId: string;
|
|
38
|
+
shots: {
|
|
39
|
+
window: string;
|
|
40
|
+
app: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
data: string;
|
|
44
|
+
}[];
|
|
45
|
+
}
|
|
46
|
+
export interface ComputerRuntimeOptions {
|
|
47
|
+
target: ComputerTargetFactory;
|
|
48
|
+
/**
|
|
49
|
+
* Capture one window for the person, outside the platform layer. The host
|
|
50
|
+
* does this, not the target: a target screenshot replaces the snapshot the
|
|
51
|
+
* agent's element refs belong to, and a picture for the transcript must not
|
|
52
|
+
* cost the agent its refs. Without it, turns end with no snapshot.
|
|
53
|
+
*/
|
|
54
|
+
snapshot?: (window: string) => Promise<{
|
|
55
|
+
mimeType: string;
|
|
56
|
+
data: string;
|
|
57
|
+
} | undefined>;
|
|
58
|
+
/** Pids of the host app itself; its windows are never listed or driven. */
|
|
59
|
+
selfPids?: () => number[];
|
|
60
|
+
policy?: () => PolicyOptions;
|
|
61
|
+
/** `never` keeps the agent in the background: take_control is refused. */
|
|
62
|
+
takeover?: () => "ask" | "never";
|
|
63
|
+
arbiter?: ComputerArbiter;
|
|
64
|
+
logger?: Logger;
|
|
65
|
+
/**
|
|
66
|
+
* Read the OS grants from the host app itself, live. Preferred over asking
|
|
67
|
+
* the helper: macOS caches a process's Accessibility answer, so a helper
|
|
68
|
+
* started before the grant keeps saying no after the person said yes.
|
|
69
|
+
*/
|
|
70
|
+
permissions?: () => Promise<ComputerPermissions>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* What every conversation shares: one helper process, one arbiter.
|
|
74
|
+
*
|
|
75
|
+
* The helper starts on the first call that needs it — registered eagerly,
|
|
76
|
+
* launched lazily, the same rule as the browser — and is restarted on the next
|
|
77
|
+
* call if it dies.
|
|
78
|
+
*/
|
|
79
|
+
export declare class ComputerRuntime {
|
|
80
|
+
readonly arbiter: ComputerArbiter;
|
|
81
|
+
private readonly opts;
|
|
82
|
+
private starting?;
|
|
83
|
+
private helperInfo?;
|
|
84
|
+
private readonly observers;
|
|
85
|
+
private readonly snapshotObservers;
|
|
86
|
+
constructor(opts: ComputerRuntimeOptions);
|
|
87
|
+
target(): Promise<ComputerTarget>;
|
|
88
|
+
/** Forget a dead helper so the next call starts a fresh one. */
|
|
89
|
+
reset(): void;
|
|
90
|
+
info(): Promise<HelperInfo>;
|
|
91
|
+
private granted?;
|
|
92
|
+
permissions(): Promise<ComputerPermissions>;
|
|
93
|
+
requestPermissions(grant?: keyof ComputerPermissions): Promise<void>;
|
|
94
|
+
selfPids(): Set<number>;
|
|
95
|
+
policy(): PolicyOptions;
|
|
96
|
+
takeover(): "ask" | "never";
|
|
97
|
+
onAction(listener: (event: ComputerActionEvent) => void): () => void;
|
|
98
|
+
emit(event: ComputerActionEvent): void;
|
|
99
|
+
canSnapshot(): boolean;
|
|
100
|
+
snapshot(window: string): Promise<{
|
|
101
|
+
mimeType: string;
|
|
102
|
+
data: string;
|
|
103
|
+
} | undefined>;
|
|
104
|
+
onSnapshot(listener: (event: ComputerSnapshotEvent) => void): () => void;
|
|
105
|
+
emitSnapshot(event: ComputerSnapshotEvent): void;
|
|
106
|
+
close(): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* One conversation's view of the computer.
|
|
110
|
+
*
|
|
111
|
+
* Holds what only makes sense per conversation: the apps and windows it has
|
|
112
|
+
* seen (so a permission prompt can name an app synchronously), the geometry of
|
|
113
|
+
* the screenshots it was shown (so its coordinates can be mapped back), and
|
|
114
|
+
* the window it last worked in.
|
|
115
|
+
*/
|
|
116
|
+
export declare class ComputerUseSession {
|
|
117
|
+
readonly runtime: ComputerRuntime;
|
|
118
|
+
private sessionId;
|
|
119
|
+
private label;
|
|
120
|
+
private readonly apps;
|
|
121
|
+
private readonly windowsById;
|
|
122
|
+
private readonly shots;
|
|
123
|
+
private readonly secureRefs;
|
|
124
|
+
/**
|
|
125
|
+
* Windows this turn worked in whose last state the agent has not seen in a
|
|
126
|
+
* screenshot of its own. Each gets one picture when the turn ends; one the
|
|
127
|
+
* agent screenshotted after its last action already has its picture in the
|
|
128
|
+
* transcript.
|
|
129
|
+
*/
|
|
130
|
+
private readonly unseen;
|
|
131
|
+
private readonly refFrames;
|
|
132
|
+
private currentWindow?;
|
|
133
|
+
constructor(runtime: ComputerRuntime, sessionId?: string);
|
|
134
|
+
bind(sessionId: string): void;
|
|
135
|
+
setLabel(label: () => string | undefined): void;
|
|
136
|
+
holder(): LeaseHolder;
|
|
137
|
+
get id(): string;
|
|
138
|
+
listApps(): Promise<AppInfo[]>;
|
|
139
|
+
listWindows(pid?: number): Promise<WindowInfo[]>;
|
|
140
|
+
private rememberApp;
|
|
141
|
+
/**
|
|
142
|
+
* The app a call names, synchronously, for the permission prompt.
|
|
143
|
+
*
|
|
144
|
+
* From what this conversation has already seen; an app it has not listed
|
|
145
|
+
* yet is named as the model wrote it, which still scopes the approval to
|
|
146
|
+
* one app.
|
|
147
|
+
*/
|
|
148
|
+
appIdFor(input: {
|
|
149
|
+
app?: string;
|
|
150
|
+
window?: string;
|
|
151
|
+
ref?: string;
|
|
152
|
+
}): string | undefined;
|
|
153
|
+
/** Find the window a call means: by ref, by id, by app, or the last one used. */
|
|
154
|
+
resolveWindow(input: {
|
|
155
|
+
app?: string;
|
|
156
|
+
window?: string;
|
|
157
|
+
ref?: string;
|
|
158
|
+
}): Promise<WindowInfo>;
|
|
159
|
+
tierOf(window: WindowInfo): ComputerTier;
|
|
160
|
+
/**
|
|
161
|
+
* Everything that has to hold before touching a window: it is not ours,
|
|
162
|
+
* its tier allows this kind of action, and no other conversation has it.
|
|
163
|
+
*/
|
|
164
|
+
guard(window: WindowInfo, kind: ActionKind): void;
|
|
165
|
+
/**
|
|
166
|
+
* Stay off a window the person is using right now.
|
|
167
|
+
*
|
|
168
|
+
* Their front window with input in the last few seconds is theirs: the
|
|
169
|
+
* lease on it lapses and the call is refused. Pointer-free actions on other
|
|
170
|
+
* windows go ahead regardless.
|
|
171
|
+
*/
|
|
172
|
+
respectUser(window: WindowInfo, target: ComputerTarget): Promise<void>;
|
|
173
|
+
/** Keys wait until the person has stopped typing, up to a limit. */
|
|
174
|
+
waitForQuiet(target: ComputerTarget, signal?: AbortSignal, quietMs?: number, maxMs?: number): Promise<void>;
|
|
175
|
+
rememberShot(key: string, shot: Shot): void;
|
|
176
|
+
/**
|
|
177
|
+
* Map a point in the last screenshot of `window` back to the screen.
|
|
178
|
+
*
|
|
179
|
+
* The model only ever sees image pixels. Retina, per-monitor DPI and the
|
|
180
|
+
* downscale to fit the image budget are all folded into the screenshot's own
|
|
181
|
+
* frame, so none of them reach the model.
|
|
182
|
+
*/
|
|
183
|
+
toScreen(window: WindowInfo, x: number, y: number): {
|
|
184
|
+
x: number;
|
|
185
|
+
y: number;
|
|
186
|
+
};
|
|
187
|
+
rememberTree(nodes: AxNode[]): void;
|
|
188
|
+
isSecure(ref: string): boolean;
|
|
189
|
+
frameOf(ref: string): Rect | undefined;
|
|
190
|
+
announce(event: Omit<ComputerActionEvent, "sessionId" | "label">, target?: ComputerTarget): Promise<void>;
|
|
191
|
+
/** The agent's own screenshot of this window: the transcript already shows its state. */
|
|
192
|
+
sawWindow(window: string): void;
|
|
193
|
+
/** The turn ended: let go of windows and control, so others need not wait out the lease. */
|
|
194
|
+
endTurn(): void;
|
|
195
|
+
private snapshotTurn;
|
|
196
|
+
close(): Promise<void>;
|
|
197
|
+
}
|
|
198
|
+
/** Refs look like `w<window>.<n>`; the window id is everything between. */
|
|
199
|
+
export declare function windowOfRef(ref: string): string | undefined;
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { ComputerArbiter } from "./arbiter.js";
|
|
2
|
+
import { tierAllows, tierFor, tierRefusal } from "./policy.js";
|
|
3
|
+
import { ComputerError } from "./target.js";
|
|
4
|
+
/**
|
|
5
|
+
* What every conversation shares: one helper process, one arbiter.
|
|
6
|
+
*
|
|
7
|
+
* The helper starts on the first call that needs it — registered eagerly,
|
|
8
|
+
* launched lazily, the same rule as the browser — and is restarted on the next
|
|
9
|
+
* call if it dies.
|
|
10
|
+
*/
|
|
11
|
+
export class ComputerRuntime {
|
|
12
|
+
arbiter;
|
|
13
|
+
opts;
|
|
14
|
+
starting;
|
|
15
|
+
helperInfo;
|
|
16
|
+
observers = new Set();
|
|
17
|
+
snapshotObservers = new Set();
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
this.opts = opts;
|
|
20
|
+
this.arbiter = opts.arbiter ?? new ComputerArbiter();
|
|
21
|
+
}
|
|
22
|
+
async target() {
|
|
23
|
+
if (!this.starting) {
|
|
24
|
+
this.starting = this.opts.target().catch((err) => {
|
|
25
|
+
this.starting = undefined;
|
|
26
|
+
throw err;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return this.starting;
|
|
30
|
+
}
|
|
31
|
+
/** Forget a dead helper so the next call starts a fresh one. */
|
|
32
|
+
reset() {
|
|
33
|
+
const old = this.starting;
|
|
34
|
+
this.starting = undefined;
|
|
35
|
+
this.helperInfo = undefined;
|
|
36
|
+
void old?.then((target) => target.close()).catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
async info() {
|
|
39
|
+
if (!this.helperInfo)
|
|
40
|
+
this.helperInfo = await (await this.target()).info();
|
|
41
|
+
return this.helperInfo;
|
|
42
|
+
}
|
|
43
|
+
granted;
|
|
44
|
+
async permissions() {
|
|
45
|
+
const now = this.opts.permissions ? await this.opts.permissions() : await (await this.target()).permissions();
|
|
46
|
+
// A grant that just arrived is invisible to a helper started before it:
|
|
47
|
+
// start a fresh one, which asks the OS again.
|
|
48
|
+
const before = this.granted;
|
|
49
|
+
if (before && ((now.accessibility && !before.accessibility) || (now.screen && !before.screen))) {
|
|
50
|
+
this.reset();
|
|
51
|
+
}
|
|
52
|
+
this.granted = now;
|
|
53
|
+
return now;
|
|
54
|
+
}
|
|
55
|
+
async requestPermissions(grant) {
|
|
56
|
+
await (await this.target()).requestPermissions(grant);
|
|
57
|
+
}
|
|
58
|
+
selfPids() {
|
|
59
|
+
return new Set(this.opts.selfPids?.() ?? [process.pid]);
|
|
60
|
+
}
|
|
61
|
+
policy() {
|
|
62
|
+
return this.opts.policy?.() ?? {};
|
|
63
|
+
}
|
|
64
|
+
takeover() {
|
|
65
|
+
return this.opts.takeover?.() ?? "ask";
|
|
66
|
+
}
|
|
67
|
+
onAction(listener) {
|
|
68
|
+
this.observers.add(listener);
|
|
69
|
+
return () => this.observers.delete(listener);
|
|
70
|
+
}
|
|
71
|
+
emit(event) {
|
|
72
|
+
for (const listener of this.observers) {
|
|
73
|
+
try {
|
|
74
|
+
listener(event);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// An overlay that throws must not fail the action it was drawing.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
canSnapshot() {
|
|
82
|
+
return Boolean(this.opts.snapshot);
|
|
83
|
+
}
|
|
84
|
+
async snapshot(window) {
|
|
85
|
+
return this.opts.snapshot?.(window).catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
onSnapshot(listener) {
|
|
88
|
+
this.snapshotObservers.add(listener);
|
|
89
|
+
return () => this.snapshotObservers.delete(listener);
|
|
90
|
+
}
|
|
91
|
+
emitSnapshot(event) {
|
|
92
|
+
for (const listener of this.snapshotObservers) {
|
|
93
|
+
try {
|
|
94
|
+
listener(event);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// A transcript that cannot take the picture must not fail the turn.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async close() {
|
|
102
|
+
const target = this.starting;
|
|
103
|
+
this.starting = undefined;
|
|
104
|
+
await target?.then((t) => t.close()).catch(() => { });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* One conversation's view of the computer.
|
|
109
|
+
*
|
|
110
|
+
* Holds what only makes sense per conversation: the apps and windows it has
|
|
111
|
+
* seen (so a permission prompt can name an app synchronously), the geometry of
|
|
112
|
+
* the screenshots it was shown (so its coordinates can be mapped back), and
|
|
113
|
+
* the window it last worked in.
|
|
114
|
+
*/
|
|
115
|
+
export class ComputerUseSession {
|
|
116
|
+
runtime;
|
|
117
|
+
sessionId = "";
|
|
118
|
+
label = () => undefined;
|
|
119
|
+
apps = new Map();
|
|
120
|
+
windowsById = new Map();
|
|
121
|
+
shots = new Map();
|
|
122
|
+
secureRefs = new Set();
|
|
123
|
+
/**
|
|
124
|
+
* Windows this turn worked in whose last state the agent has not seen in a
|
|
125
|
+
* screenshot of its own. Each gets one picture when the turn ends; one the
|
|
126
|
+
* agent screenshotted after its last action already has its picture in the
|
|
127
|
+
* transcript.
|
|
128
|
+
*/
|
|
129
|
+
unseen = new Map();
|
|
130
|
+
refFrames = new Map();
|
|
131
|
+
currentWindow;
|
|
132
|
+
constructor(runtime, sessionId) {
|
|
133
|
+
this.runtime = runtime;
|
|
134
|
+
if (sessionId)
|
|
135
|
+
this.sessionId = sessionId;
|
|
136
|
+
}
|
|
137
|
+
bind(sessionId) {
|
|
138
|
+
if (!this.sessionId)
|
|
139
|
+
this.sessionId = sessionId;
|
|
140
|
+
}
|
|
141
|
+
setLabel(label) {
|
|
142
|
+
this.label = label;
|
|
143
|
+
}
|
|
144
|
+
holder() {
|
|
145
|
+
return { sessionId: this.sessionId, label: this.label() ?? "another conversation" };
|
|
146
|
+
}
|
|
147
|
+
get id() {
|
|
148
|
+
return this.sessionId;
|
|
149
|
+
}
|
|
150
|
+
// ---- lookups -----------------------------------------------------------
|
|
151
|
+
async listApps() {
|
|
152
|
+
const target = await this.runtime.target();
|
|
153
|
+
const self = this.runtime.selfPids();
|
|
154
|
+
const apps = (await target.apps()).filter((app) => !self.has(app.pid));
|
|
155
|
+
for (const app of apps)
|
|
156
|
+
this.rememberApp(app);
|
|
157
|
+
return apps;
|
|
158
|
+
}
|
|
159
|
+
async listWindows(pid) {
|
|
160
|
+
const target = await this.runtime.target();
|
|
161
|
+
const self = this.runtime.selfPids();
|
|
162
|
+
const windows = (await target.windows(pid === undefined ? {} : { pid })).filter((w) => !self.has(w.pid));
|
|
163
|
+
for (const window of windows)
|
|
164
|
+
this.windowsById.set(window.id, window);
|
|
165
|
+
return windows;
|
|
166
|
+
}
|
|
167
|
+
rememberApp(app) {
|
|
168
|
+
this.apps.set(app.id.toLowerCase(), app);
|
|
169
|
+
this.apps.set(app.name.toLowerCase(), app);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The app a call names, synchronously, for the permission prompt.
|
|
173
|
+
*
|
|
174
|
+
* From what this conversation has already seen; an app it has not listed
|
|
175
|
+
* yet is named as the model wrote it, which still scopes the approval to
|
|
176
|
+
* one app.
|
|
177
|
+
*/
|
|
178
|
+
appIdFor(input) {
|
|
179
|
+
const window = input.ref ? windowOfRef(input.ref) : input.window;
|
|
180
|
+
if (window) {
|
|
181
|
+
const known = this.windowsById.get(window);
|
|
182
|
+
if (known)
|
|
183
|
+
return known.appId;
|
|
184
|
+
}
|
|
185
|
+
if (input.app)
|
|
186
|
+
return this.apps.get(input.app.toLowerCase())?.id ?? input.app.toLowerCase();
|
|
187
|
+
if (!window && this.currentWindow)
|
|
188
|
+
return this.windowsById.get(this.currentWindow)?.appId;
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
/** Find the window a call means: by ref, by id, by app, or the last one used. */
|
|
192
|
+
async resolveWindow(input) {
|
|
193
|
+
const wanted = input.ref ? windowOfRef(input.ref) : input.window;
|
|
194
|
+
if (wanted) {
|
|
195
|
+
let window = this.windowsById.get(wanted);
|
|
196
|
+
if (!window)
|
|
197
|
+
window = (await this.listWindows()).find((w) => w.id === wanted);
|
|
198
|
+
if (!window)
|
|
199
|
+
throw new ComputerError("not_found", `No window ${wanted}. Call computer_list_apps to see what is open.`);
|
|
200
|
+
return window;
|
|
201
|
+
}
|
|
202
|
+
if (input.app) {
|
|
203
|
+
const key = input.app.toLowerCase();
|
|
204
|
+
let app = this.apps.get(key);
|
|
205
|
+
if (!app) {
|
|
206
|
+
await this.listApps();
|
|
207
|
+
app = this.apps.get(key) ?? [...new Set(this.apps.values())].find((a) => a.name.toLowerCase().includes(key));
|
|
208
|
+
}
|
|
209
|
+
if (!app)
|
|
210
|
+
throw new ComputerError("not_found", `${input.app} is not running. Use computer_open_app to start it.`);
|
|
211
|
+
const windows = (await this.listWindows(app.pid)).filter((w) => !w.minimized);
|
|
212
|
+
const window = windows.find((w) => w.focused) ?? windows[0];
|
|
213
|
+
if (!window)
|
|
214
|
+
throw new ComputerError("not_found", `${app.name} has no open window.`);
|
|
215
|
+
return window;
|
|
216
|
+
}
|
|
217
|
+
if (this.currentWindow) {
|
|
218
|
+
const window = this.windowsById.get(this.currentWindow);
|
|
219
|
+
if (window)
|
|
220
|
+
return window;
|
|
221
|
+
}
|
|
222
|
+
throw new ComputerError("not_found", "Name an app or a window. Call computer_list_apps to see what is open.");
|
|
223
|
+
}
|
|
224
|
+
// ---- guards ------------------------------------------------------------
|
|
225
|
+
tierOf(window) {
|
|
226
|
+
return tierFor(window.appId, window.app, this.runtime.policy());
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Everything that has to hold before touching a window: it is not ours,
|
|
230
|
+
* its tier allows this kind of action, and no other conversation has it.
|
|
231
|
+
*/
|
|
232
|
+
guard(window, kind) {
|
|
233
|
+
if (this.runtime.selfPids().has(window.pid)) {
|
|
234
|
+
throw new ComputerError("refused", "That window belongs to OHarness itself, which cannot be controlled by the agent.");
|
|
235
|
+
}
|
|
236
|
+
const tier = this.tierOf(window);
|
|
237
|
+
if (!tierAllows(tier, kind))
|
|
238
|
+
throw new ComputerError("refused", tierRefusal(tier, window.app, kind));
|
|
239
|
+
if (kind !== "look") {
|
|
240
|
+
this.runtime.arbiter.claimWindow(this.holder(), window.id);
|
|
241
|
+
if (kind === "type")
|
|
242
|
+
this.runtime.arbiter.claimApp(this.holder(), window.pid);
|
|
243
|
+
}
|
|
244
|
+
this.currentWindow = window.id;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Stay off a window the person is using right now.
|
|
248
|
+
*
|
|
249
|
+
* Their front window with input in the last few seconds is theirs: the
|
|
250
|
+
* lease on it lapses and the call is refused. Pointer-free actions on other
|
|
251
|
+
* windows go ahead regardless.
|
|
252
|
+
*/
|
|
253
|
+
async respectUser(window, target) {
|
|
254
|
+
if (this.runtime.arbiter.holdsControl(this.sessionId))
|
|
255
|
+
return;
|
|
256
|
+
const [front, idle] = await Promise.all([target.frontmost().catch(() => undefined), target.idle().catch(() => Infinity)]);
|
|
257
|
+
if (front && idle < 3_000 && (front.window === window.id || (!front.window && front.pid === window.pid))) {
|
|
258
|
+
this.runtime.arbiter.yieldWindow(window.id);
|
|
259
|
+
throw new ComputerError("busy", `The user is working in ${window.app} right now. Wait, or work on something else.`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** Keys wait until the person has stopped typing, up to a limit. */
|
|
263
|
+
async waitForQuiet(target, signal, quietMs = 1_500, maxMs = 10_000) {
|
|
264
|
+
if (this.runtime.arbiter.holdsControl(this.sessionId))
|
|
265
|
+
return;
|
|
266
|
+
const started = Date.now();
|
|
267
|
+
for (;;) {
|
|
268
|
+
const idle = await target.idle().catch(() => Infinity);
|
|
269
|
+
if (idle >= quietMs)
|
|
270
|
+
return;
|
|
271
|
+
if (Date.now() - started > maxMs) {
|
|
272
|
+
throw new ComputerError("busy", "The user has been typing continuously; try again when they pause.");
|
|
273
|
+
}
|
|
274
|
+
if (signal?.aborted)
|
|
275
|
+
throw new ComputerError("refused", "stopped");
|
|
276
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(500, quietMs - idle + 50)));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// ---- screenshots and coordinates ---------------------------------------
|
|
280
|
+
rememberShot(key, shot) {
|
|
281
|
+
this.shots.set(key, { width: shot.width, height: shot.height, frame: shot.frame });
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Map a point in the last screenshot of `window` back to the screen.
|
|
285
|
+
*
|
|
286
|
+
* The model only ever sees image pixels. Retina, per-monitor DPI and the
|
|
287
|
+
* downscale to fit the image budget are all folded into the screenshot's own
|
|
288
|
+
* frame, so none of them reach the model.
|
|
289
|
+
*/
|
|
290
|
+
toScreen(window, x, y) {
|
|
291
|
+
const shot = this.shots.get(window.id);
|
|
292
|
+
if (!shot) {
|
|
293
|
+
throw new ComputerError("refused", `Take a computer_screenshot of ${window.app} first; x/y are pixels in that screenshot. Or act on a ref from computer_read_app.`);
|
|
294
|
+
}
|
|
295
|
+
if (x < 0 || y < 0 || x > shot.width || y > shot.height) {
|
|
296
|
+
throw new ComputerError("refused", `(${x}, ${y}) is outside the ${shot.width}x${shot.height} screenshot.`);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
x: shot.frame.x + (x * shot.frame.w) / shot.width,
|
|
300
|
+
y: shot.frame.y + (y * shot.frame.h) / shot.height,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// ---- accessibility refs ------------------------------------------------
|
|
304
|
+
rememberTree(nodes) {
|
|
305
|
+
for (const node of nodes) {
|
|
306
|
+
if (node.secure)
|
|
307
|
+
this.secureRefs.add(node.ref);
|
|
308
|
+
if (node.frame)
|
|
309
|
+
this.refFrames.set(node.ref, node.frame);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
isSecure(ref) {
|
|
313
|
+
return this.secureRefs.has(ref);
|
|
314
|
+
}
|
|
315
|
+
frameOf(ref) {
|
|
316
|
+
return this.refFrames.get(ref);
|
|
317
|
+
}
|
|
318
|
+
// ---- presentation ------------------------------------------------------
|
|
319
|
+
async announce(event, target) {
|
|
320
|
+
const known = event.window ? this.windowsById.get(event.window) : undefined;
|
|
321
|
+
// Opening or reading a window has no point of its own, and without one the
|
|
322
|
+
// cursor stayed wherever the last click was — or nowhere — while the agent
|
|
323
|
+
// had moved on to another app. The window's middle says where it is now.
|
|
324
|
+
if (event.kind === "look" && !event.point && known?.frame) {
|
|
325
|
+
event = { ...event, point: { x: known.frame.x + known.frame.w / 2, y: known.frame.y + known.frame.h / 2 } };
|
|
326
|
+
}
|
|
327
|
+
let visible = event.visible;
|
|
328
|
+
if (visible === undefined && event.point && event.window && target) {
|
|
329
|
+
visible = await target.pointVisible(event.window, event.point.x, event.point.y).catch(() => false);
|
|
330
|
+
}
|
|
331
|
+
if (event.window && event.kind !== "control" && event.kind !== "release") {
|
|
332
|
+
// Re-inserted, so the order is the order the windows were last used in.
|
|
333
|
+
this.unseen.delete(event.window);
|
|
334
|
+
this.unseen.set(event.window, event.app ?? known?.app ?? "");
|
|
335
|
+
}
|
|
336
|
+
this.runtime.emit({
|
|
337
|
+
...event,
|
|
338
|
+
...(visible === undefined ? {} : { visible }),
|
|
339
|
+
...(known ? { windowFrame: known.frame, ...(known.title ? { title: known.title } : {}) } : {}),
|
|
340
|
+
sessionId: this.sessionId,
|
|
341
|
+
label: this.holder().label,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/** The agent's own screenshot of this window: the transcript already shows its state. */
|
|
345
|
+
sawWindow(window) {
|
|
346
|
+
this.unseen.delete(window);
|
|
347
|
+
}
|
|
348
|
+
/** The turn ended: let go of windows and control, so others need not wait out the lease. */
|
|
349
|
+
endTurn() {
|
|
350
|
+
this.runtime.arbiter.releaseAll(this.sessionId);
|
|
351
|
+
// The idle event first, synchronously: the host marks where in the
|
|
352
|
+
// conversation this turn ended on it, before a queued message can start
|
|
353
|
+
// the next one. The pictures follow when they are taken.
|
|
354
|
+
this.runtime.emit({ sessionId: this.sessionId, label: this.holder().label, kind: "idle" });
|
|
355
|
+
const windows = [...this.unseen].slice(-SNAPSHOT_MAX_WINDOWS);
|
|
356
|
+
this.unseen.clear();
|
|
357
|
+
if (windows.length && this.runtime.canSnapshot())
|
|
358
|
+
void this.snapshotTurn(windows);
|
|
359
|
+
}
|
|
360
|
+
async snapshotTurn(windows) {
|
|
361
|
+
const shots = [];
|
|
362
|
+
for (const [window, app] of windows) {
|
|
363
|
+
const image = await this.runtime.snapshot(window);
|
|
364
|
+
if (!image)
|
|
365
|
+
continue;
|
|
366
|
+
const title = this.windowsById.get(window)?.title;
|
|
367
|
+
shots.push({ window, app, ...(title ? { title } : {}), ...image });
|
|
368
|
+
}
|
|
369
|
+
if (shots.length)
|
|
370
|
+
this.runtime.emitSnapshot({ sessionId: this.sessionId, shots });
|
|
371
|
+
}
|
|
372
|
+
async close() {
|
|
373
|
+
// Closing is not the end of a turn anyone will read back.
|
|
374
|
+
this.unseen.clear();
|
|
375
|
+
this.endTurn();
|
|
376
|
+
this.shots.clear();
|
|
377
|
+
this.windowsById.clear();
|
|
378
|
+
this.apps.clear();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* At most this many windows get a picture per turn: a turn that went through
|
|
383
|
+
* six apps is read back by its last few, and each picture is a capture and a
|
|
384
|
+
* file.
|
|
385
|
+
*/
|
|
386
|
+
const SNAPSHOT_MAX_WINDOWS = 3;
|
|
387
|
+
/** Refs look like `w<window>.<n>`; the window id is everything between. */
|
|
388
|
+
export function windowOfRef(ref) {
|
|
389
|
+
const match = /^w(.+)\.\d+$/.exec(ref);
|
|
390
|
+
return match?.[1];
|
|
391
|
+
}
|
|
392
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/computer/session.ts"],"names":[],"mappings":"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"}
|