@mind-harness/mh-browser 0.2.0 → 0.2.1
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/extension/manifest.json +1 -1
- package/lib/index.js +87 -25
- package/lib/typert.host.js +1 -1
- package/lib/typert.remote-client.js +1 -1
- package/lib/types/service/service.d.ts +8 -4
- package/lib/types/tools/session.d.ts +3 -1
- package/lib/types/types.d.ts +8 -5
- package/lib/types/words.d.ts +7 -0
- package/package.json +1 -1
package/extension/manifest.json
CHANGED
package/lib/index.js
CHANGED
|
@@ -447,7 +447,6 @@ function formatSeconds(seconds) {
|
|
|
447
447
|
}
|
|
448
448
|
//#endregion
|
|
449
449
|
//#region lib/types/types.js
|
|
450
|
-
/** Public browser types. Playwright types stay inside the service. */
|
|
451
450
|
var MhBrowserError = class extends Error {
|
|
452
451
|
code;
|
|
453
452
|
page;
|
|
@@ -479,10 +478,12 @@ function unknownTab() {
|
|
|
479
478
|
//#region lib/types/tools/session.js
|
|
480
479
|
/** dsh shows the model only the message, so the message starts with the code. */
|
|
481
480
|
var BrowserToolError = class extends HarnessError {
|
|
481
|
+
code;
|
|
482
482
|
reason;
|
|
483
483
|
constructor(code, reason) {
|
|
484
484
|
super(`${code}: ${reason}`, code);
|
|
485
485
|
this.name = "BrowserToolError";
|
|
486
|
+
this.code = code;
|
|
486
487
|
this.reason = reason;
|
|
487
488
|
}
|
|
488
489
|
};
|
|
@@ -1063,7 +1064,7 @@ const IMAGE_VALUE = {
|
|
|
1063
1064
|
const TAB$1 = "Tab id copied from the latest result in this session: a tabs list, or a page element's tab attribute. Omit it to use the tab of that latest result; if it has no tab, the call fails with INVALID_ARGS. An idle tab may be closed, and a closed id fails with UNKNOWN_TAB: open the address again with browser_open. A tab with unsubmitted input is marked in use and is not closed, and opening or a declared action does not reload it. Tabs are gone after a restart. A page with an Agent View has no tab until you open it with snapshot.";
|
|
1064
1065
|
const TARGET = "A ref copied from this tab's latest snapshot, such as e3, or a selector that matches one element. A ref that is not in the current snapshot fails with STALE_REF.";
|
|
1065
1066
|
const ELEMENT = "What the person sees in the log. It does not locate the element.";
|
|
1066
|
-
const FILENAME = "A path inside the workspace. The result is saved there and the reply is the path and the byte count. Omit it and the result stays in the reply.";
|
|
1067
|
+
const FILENAME = "A path inside the workspace. The result is saved there and the reply is the path and the byte count. A file already at that path is replaced. Omit it and the result stays in the reply.";
|
|
1067
1068
|
const OUTPUT = {
|
|
1068
1069
|
schema: {
|
|
1069
1070
|
type: "object",
|
|
@@ -2961,6 +2962,7 @@ async function launchBrowser(options) {
|
|
|
2961
2962
|
acceptDownloads: true,
|
|
2962
2963
|
chromiumSandbox: chromiumSandboxEnabled(options.browser),
|
|
2963
2964
|
...options.headless ? {} : {
|
|
2965
|
+
viewport: null,
|
|
2964
2966
|
ignoreDefaultArgs: ["--disable-extensions"],
|
|
2965
2967
|
args: ["--enable-unsafe-extension-debugging", "--keep-alive-for-test"]
|
|
2966
2968
|
},
|
|
@@ -4096,6 +4098,16 @@ function watchDialog(page) {
|
|
|
4096
4098
|
};
|
|
4097
4099
|
}
|
|
4098
4100
|
//#endregion
|
|
4101
|
+
//#region lib/types/words.js
|
|
4102
|
+
/** Shown on a session's tab group while a handover is waiting. */
|
|
4103
|
+
const WAITING_TITLE = "等你:";
|
|
4104
|
+
/** The question on the handover card. `reason` is the sentence the model gave. */
|
|
4105
|
+
function handoverQuestion(reason) {
|
|
4106
|
+
return `浏览器交给你了:${reason}`;
|
|
4107
|
+
}
|
|
4108
|
+
/** The option that hands the browser back. */
|
|
4109
|
+
const HAND_BACK = "交回";
|
|
4110
|
+
//#endregion
|
|
4099
4111
|
//#region lib/types/service/extension.js
|
|
4100
4112
|
const PACKAGE = "@mind-harness/mh-browser";
|
|
4101
4113
|
const WORKER_MS = 5e3;
|
|
@@ -4760,7 +4772,7 @@ var Windows = class {
|
|
|
4760
4772
|
if (extension === void 0 || groupId === void 0) return;
|
|
4761
4773
|
const title = this.titles.get(owner) ?? "";
|
|
4762
4774
|
const waiting = this.waiting.has(owner);
|
|
4763
|
-
await extension.styleGroup(groupId, waiting ?
|
|
4775
|
+
await extension.styleGroup(groupId, waiting ? `${WAITING_TITLE}${title}` : title, waiting ? "red" : "blue");
|
|
4764
4776
|
}
|
|
4765
4777
|
async ingest(page) {
|
|
4766
4778
|
if (this.byPage.has(page)) return;
|
|
@@ -4997,6 +5009,9 @@ const DOWNLOAD_EVENT_MS = 3e3;
|
|
|
4997
5009
|
/** More exits than this within the window and the browser is not started again until one ages out. */
|
|
4998
5010
|
const RELAUNCH_LIMIT = 3;
|
|
4999
5011
|
const RELAUNCH_WINDOW_MS = 6e4;
|
|
5012
|
+
/** Agent Views remembered for a later conditional read. Older ones are read again in full. */
|
|
5013
|
+
const DOCUMENT_CAP = 64;
|
|
5014
|
+
const OPEN_ADDRESS_REASON = "only http and https addresses are opened";
|
|
5000
5015
|
const STOP_WAIT_MS = 5e3;
|
|
5001
5016
|
const WAITING_STOPPED = "stopped while waiting";
|
|
5002
5017
|
const STOPPED = Symbol("stopped");
|
|
@@ -5040,10 +5055,10 @@ let MhBrowserService = (() => {
|
|
|
5040
5055
|
windows = (__runInitializers(this, _instanceExtraInitializers), new Windows());
|
|
5041
5056
|
launchOptions;
|
|
5042
5057
|
context;
|
|
5043
|
-
ready;
|
|
5058
|
+
ready = Promise.resolve();
|
|
5044
5059
|
closing = false;
|
|
5045
|
-
/** The browser
|
|
5046
|
-
exited =
|
|
5060
|
+
/** The browser is not running. The next call that needs a page starts it. */
|
|
5061
|
+
exited = true;
|
|
5047
5062
|
exits = [];
|
|
5048
5063
|
/** One queue per owner: a slow wait in one Session does not hold up another. */
|
|
5049
5064
|
queues = /* @__PURE__ */ new Map();
|
|
@@ -5073,7 +5088,7 @@ let MhBrowserService = (() => {
|
|
|
5073
5088
|
this.windows.onTabClosed((tab) => {
|
|
5074
5089
|
this.shown.delete(tab.id);
|
|
5075
5090
|
});
|
|
5076
|
-
this.
|
|
5091
|
+
this.up().catch(() => void 0);
|
|
5077
5092
|
ctx.on("session/disposed", (session) => {
|
|
5078
5093
|
const owner = session.id;
|
|
5079
5094
|
if (owner === void 0) return;
|
|
@@ -5478,6 +5493,10 @@ let MhBrowserService = (() => {
|
|
|
5478
5493
|
* the tab, and that tab is not listed as closed.
|
|
5479
5494
|
*/
|
|
5480
5495
|
async openAddress(owner, item, signal) {
|
|
5496
|
+
if (!openableAddress(item.url)) return {
|
|
5497
|
+
url: item.url,
|
|
5498
|
+
reason: OPEN_ADDRESS_REASON
|
|
5499
|
+
};
|
|
5481
5500
|
const wantsTab = owner === "person" || item.snapshot === true || item.waitFor !== void 0;
|
|
5482
5501
|
if (!wantsTab && this.knownOrigin(item.url)) {
|
|
5483
5502
|
const via = await this.readKnown(owner, item.url, signal);
|
|
@@ -5520,7 +5539,7 @@ let MhBrowserService = (() => {
|
|
|
5520
5539
|
if (!(representation.kind === "agent-view" || representation.kind === "snapshot" && representation.agentView !== void 0)) return;
|
|
5521
5540
|
this.rememberOrigin(opened.view.url);
|
|
5522
5541
|
const shown = this.shown.get(opened.live.id);
|
|
5523
|
-
if (shown?.kind === "agent-view") this.
|
|
5542
|
+
if (shown?.kind === "agent-view") this.rememberDocument(shown.pageUrl, shown);
|
|
5524
5543
|
}
|
|
5525
5544
|
/**
|
|
5526
5545
|
* Read a known origin without a tab. `undefined` means this page has to be
|
|
@@ -5564,10 +5583,21 @@ let MhBrowserService = (() => {
|
|
|
5564
5583
|
});
|
|
5565
5584
|
if (stopped(signal)) return STOPPED;
|
|
5566
5585
|
if (shown.kind !== "agent-view") return void 0;
|
|
5567
|
-
this.
|
|
5586
|
+
this.rememberDocument(pageUrl, shown);
|
|
5568
5587
|
this.rememberOrigin(pageUrl);
|
|
5569
5588
|
return this.pageOfShown(owner, shown);
|
|
5570
5589
|
}
|
|
5590
|
+
/** Keep the newest Agent Views. A dropped one is read in full the next time. */
|
|
5591
|
+
rememberDocument(url, shown) {
|
|
5592
|
+
const key = canonical(url);
|
|
5593
|
+
this.documents.delete(key);
|
|
5594
|
+
this.documents.set(key, shown);
|
|
5595
|
+
while (this.documents.size > DOCUMENT_CAP) {
|
|
5596
|
+
const oldest = this.documents.keys().next().value;
|
|
5597
|
+
if (oldest === void 0) return;
|
|
5598
|
+
this.documents.delete(oldest);
|
|
5599
|
+
}
|
|
5600
|
+
}
|
|
5571
5601
|
/** One page from a document, with no tab. */
|
|
5572
5602
|
pageOfShown(owner, shown) {
|
|
5573
5603
|
const view = {
|
|
@@ -6040,7 +6070,10 @@ let MhBrowserService = (() => {
|
|
|
6040
6070
|
});
|
|
6041
6071
|
}
|
|
6042
6072
|
async aria(tab) {
|
|
6043
|
-
return tab.page.ariaSnapshot({ mode: "ai" }).catch(() =>
|
|
6073
|
+
return tab.page.ariaSnapshot({ mode: "ai" }).catch((error) => {
|
|
6074
|
+
this.ctx.logger.debug("aria snapshot failed: %s", errorText(error));
|
|
6075
|
+
return "";
|
|
6076
|
+
});
|
|
6044
6077
|
}
|
|
6045
6078
|
async pageFromShown(tab, shown, extra) {
|
|
6046
6079
|
const current = shown ?? {
|
|
@@ -6050,7 +6083,10 @@ let MhBrowserService = (() => {
|
|
|
6050
6083
|
text: "",
|
|
6051
6084
|
snapshot: ""
|
|
6052
6085
|
};
|
|
6053
|
-
const title = tab.dialogHeld ? "" : await tab.page.title().catch(() =>
|
|
6086
|
+
const title = tab.dialogHeld ? "" : await tab.page.title().catch((error) => {
|
|
6087
|
+
this.ctx.logger.debug("page title failed: %s", errorText(error));
|
|
6088
|
+
return "";
|
|
6089
|
+
});
|
|
6054
6090
|
this.windows.noteTitle(tab, title);
|
|
6055
6091
|
const view = {
|
|
6056
6092
|
tab: tab.id,
|
|
@@ -6215,8 +6251,9 @@ let MhBrowserService = (() => {
|
|
|
6215
6251
|
...location === void 0 || location === "" ? {} : { location },
|
|
6216
6252
|
...mediaType === void 0 ? {} : { mediaType }
|
|
6217
6253
|
};
|
|
6218
|
-
} catch {
|
|
6254
|
+
} catch (error) {
|
|
6219
6255
|
if (signal?.aborted === true) throw new MhBrowserError(INTERRUPTED, "stopped after sending; it may have taken effect");
|
|
6256
|
+
this.ctx.logger.debug("declared action was not answered: %s", errorText(error));
|
|
6220
6257
|
return { kind: "lost" };
|
|
6221
6258
|
}
|
|
6222
6259
|
}
|
|
@@ -6318,11 +6355,18 @@ let MhBrowserService = (() => {
|
|
|
6318
6355
|
async start() {
|
|
6319
6356
|
const context = await launchBrowser(this.launchOptions);
|
|
6320
6357
|
if (this.closing) {
|
|
6321
|
-
await
|
|
6358
|
+
await this.closeContext(context);
|
|
6322
6359
|
return;
|
|
6323
6360
|
}
|
|
6324
6361
|
this.context = context;
|
|
6325
|
-
|
|
6362
|
+
try {
|
|
6363
|
+
await this.windows.attach(context, this.launchOptions.profileDir, { headed: !this.launchOptions.headless });
|
|
6364
|
+
} catch (error) {
|
|
6365
|
+
this.context = void 0;
|
|
6366
|
+
this.windows.dropPages();
|
|
6367
|
+
await this.closeContext(context);
|
|
6368
|
+
throw error;
|
|
6369
|
+
}
|
|
6326
6370
|
context.browser()?.on("disconnected", () => {
|
|
6327
6371
|
if (this.closing || this.context !== context) return;
|
|
6328
6372
|
this.onExit();
|
|
@@ -6338,22 +6382,23 @@ let MhBrowserService = (() => {
|
|
|
6338
6382
|
this.ready = Promise.resolve();
|
|
6339
6383
|
}
|
|
6340
6384
|
/**
|
|
6341
|
-
* The browser for a call that needs a page. One that
|
|
6342
|
-
* here. The exit limit stops unattended restarts; a person's request
|
|
6343
|
-
* one start per click and skips it.
|
|
6385
|
+
* The browser for a call that needs a page. One that is not running starts
|
|
6386
|
+
* again here. The exit limit stops unattended restarts; a person's request
|
|
6387
|
+
* is one start per click and skips it.
|
|
6344
6388
|
*/
|
|
6345
6389
|
up(byPerson = false) {
|
|
6346
6390
|
if (!this.exited || this.closing) return this.ready;
|
|
6347
6391
|
const now = Date.now();
|
|
6348
6392
|
while (this.exits.length > 0 && now - (this.exits[0] ?? now) > RELAUNCH_WINDOW_MS) this.exits.shift();
|
|
6349
6393
|
if (!byPerson && this.exits.length > RELAUNCH_LIMIT) {
|
|
6350
|
-
this.ctx.logger.warn("browser keeps
|
|
6351
|
-
return Promise.reject(new MhBrowserError(BROWSER_UNAVAILABLE, `the browser
|
|
6394
|
+
this.ctx.logger.warn("browser keeps stopping; not starting it again yet");
|
|
6395
|
+
return Promise.reject(new MhBrowserError(BROWSER_UNAVAILABLE, `the browser stopped or did not start ${String(this.exits.length)} times within ${String(RELAUNCH_WINDOW_MS / 1e3)} s; try again in a minute`));
|
|
6352
6396
|
}
|
|
6353
6397
|
this.exited = false;
|
|
6354
6398
|
const started = this.launch();
|
|
6355
6399
|
started.then(() => this.windows.resumePersonInput(), () => {
|
|
6356
6400
|
this.exited = true;
|
|
6401
|
+
if (!this.closing) this.exits.push(Date.now());
|
|
6357
6402
|
});
|
|
6358
6403
|
this.ready = started;
|
|
6359
6404
|
return started;
|
|
@@ -6361,10 +6406,15 @@ let MhBrowserService = (() => {
|
|
|
6361
6406
|
async stop() {
|
|
6362
6407
|
this.windows.suppressPersonInput();
|
|
6363
6408
|
await Promise.race([this.ready.catch(() => void 0), new Promise((resolve) => setTimeout(resolve, STOP_WAIT_MS))]);
|
|
6364
|
-
const
|
|
6365
|
-
await Promise.race([this.context?.close().catch(() => void 0), new Promise((resolve) => setTimeout(resolve, 1e3))]);
|
|
6366
|
-
(browser?.process?.())?.kill("SIGKILL");
|
|
6409
|
+
const context = this.context;
|
|
6367
6410
|
this.context = void 0;
|
|
6411
|
+
if (context !== void 0) await this.closeContext(context);
|
|
6412
|
+
}
|
|
6413
|
+
/** Close a context the service is done with, and kill it if close stalls. */
|
|
6414
|
+
async closeContext(context) {
|
|
6415
|
+
const browser = context.browser();
|
|
6416
|
+
await Promise.race([context.close().catch(() => void 0), new Promise((resolve) => setTimeout(resolve, 1e3))]);
|
|
6417
|
+
(browser?.process?.())?.kill("SIGKILL");
|
|
6368
6418
|
}
|
|
6369
6419
|
refuseIfPerson(owner, tab) {
|
|
6370
6420
|
if (this.control.ofTab(owner, tab) !== "person") return;
|
|
@@ -6521,6 +6571,18 @@ function requiresOf(text, pageUrl) {
|
|
|
6521
6571
|
const read = readAgentView(text, pageUrl);
|
|
6522
6572
|
return read.ok ? read.doc.requires : [];
|
|
6523
6573
|
}
|
|
6574
|
+
function openableAddress(url) {
|
|
6575
|
+
if (url === "about:blank") return true;
|
|
6576
|
+
try {
|
|
6577
|
+
const protocol = new URL(url).protocol;
|
|
6578
|
+
return protocol === "http:" || protocol === "https:";
|
|
6579
|
+
} catch {
|
|
6580
|
+
return false;
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
function errorText(error) {
|
|
6584
|
+
return error instanceof Error ? error.message : String(error);
|
|
6585
|
+
}
|
|
6524
6586
|
function canonical(url) {
|
|
6525
6587
|
try {
|
|
6526
6588
|
const parsed = new URL(url);
|
|
@@ -6760,8 +6822,8 @@ async function askUntilAnswered(ctx, reason, exec) {
|
|
|
6760
6822
|
return await Promise.race([ctx.userQuestions.ask({
|
|
6761
6823
|
questions: [{
|
|
6762
6824
|
id: "handback",
|
|
6763
|
-
question:
|
|
6764
|
-
options: [{ label:
|
|
6825
|
+
question: handoverQuestion(reason),
|
|
6826
|
+
options: [{ label: HAND_BACK }]
|
|
6765
6827
|
}],
|
|
6766
6828
|
...exec.agent !== void 0 ? { agent: exec.agent } : {},
|
|
6767
6829
|
signal: exec.signal
|
|
@@ -6921,7 +6983,7 @@ const OPEN = [
|
|
|
6921
6983
|
"A page lists documents in requires; those are not fetched with it, so open their addresses to read them or to call their actions."
|
|
6922
6984
|
].join(" ");
|
|
6923
6985
|
const PAGES = "The pages to read, 1 to 8, each returned in order as its own element.";
|
|
6924
|
-
const URL$1 = "The address to read: from a page shown to you, from the principal, or one you composed; opening a composed address is how it is checked before you use it elsewhere.";
|
|
6986
|
+
const URL$1 = "The address to read: from a page shown to you, from the principal, or one you composed; opening a composed address is how it is checked before you use it elsewhere. Only an http or https address is opened.";
|
|
6925
6987
|
const WAIT = "Optional wait after the document loads for text to appear or disappear, or for time seconds; at least one must be set. If not met, the page is still returned and waited says so.";
|
|
6926
6988
|
const SNAPSHOT = "Ask for the human page: open a tab and return its snapshot, for page operations and handover. A page without an Agent View already does.";
|
|
6927
6989
|
function browserOpenTool(ctx, reader) {
|
package/lib/typert.host.js
CHANGED
|
@@ -44,7 +44,7 @@ const $remote = createTypertRemoteInfo({
|
|
|
44
44
|
create: _mind_harness_mh_browser_mhBrowser_revealHandover_result$schema,
|
|
45
45
|
jsonSchema: {"type":"object","properties":{"status":{"type":"string","enum":["revealed","not-handing-over","no-tab"]}},"required":["status"],"additionalProperties":true},
|
|
46
46
|
},
|
|
47
|
-
sourceLocation: {"file":"packages/mh-browser/src/service/service.ts","line":
|
|
47
|
+
sourceLocation: {"file":"packages/mh-browser/src/service/service.ts","line":619,"column":9},
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
}, z)
|
|
@@ -44,7 +44,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
44
44
|
create: _mind_harness_mh_browser_mhBrowser_revealHandover_result$schema,
|
|
45
45
|
jsonSchema: {"type":"object","properties":{"status":{"type":"string","enum":["revealed","not-handing-over","no-tab"]}},"required":["status"],"additionalProperties":true},
|
|
46
46
|
},
|
|
47
|
-
sourceLocation: {"file":"packages/mh-browser/src/service/service.ts","line":
|
|
47
|
+
sourceLocation: {"file":"packages/mh-browser/src/service/service.ts","line":619,"column":9},
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
}, z)
|
|
@@ -36,7 +36,7 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
36
36
|
private context;
|
|
37
37
|
private ready;
|
|
38
38
|
private closing;
|
|
39
|
-
/** The browser
|
|
39
|
+
/** The browser is not running. The next call that needs a page starts it. */
|
|
40
40
|
private exited;
|
|
41
41
|
private readonly exits;
|
|
42
42
|
/** One queue per owner: a slow wait in one Session does not hold up another. */
|
|
@@ -170,6 +170,8 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
170
170
|
* ends the read without falling back to a tab.
|
|
171
171
|
*/
|
|
172
172
|
private readKnown;
|
|
173
|
+
/** Keep the newest Agent Views. A dropped one is read in full the next time. */
|
|
174
|
+
private rememberDocument;
|
|
173
175
|
/** One page from a document, with no tab. */
|
|
174
176
|
private pageOfShown;
|
|
175
177
|
/**
|
|
@@ -225,12 +227,14 @@ export declare class MhBrowserService extends TypertRemoteService {
|
|
|
225
227
|
/** No window opens on exit: the person may have quit it. Calls on old tabs find none. */
|
|
226
228
|
private onExit;
|
|
227
229
|
/**
|
|
228
|
-
* The browser for a call that needs a page. One that
|
|
229
|
-
* here. The exit limit stops unattended restarts; a person's request
|
|
230
|
-
* one start per click and skips it.
|
|
230
|
+
* The browser for a call that needs a page. One that is not running starts
|
|
231
|
+
* again here. The exit limit stops unattended restarts; a person's request
|
|
232
|
+
* is one start per click and skips it.
|
|
231
233
|
*/
|
|
232
234
|
private up;
|
|
233
235
|
private stop;
|
|
236
|
+
/** Close a context the service is done with, and kill it if close stalls. */
|
|
237
|
+
private closeContext;
|
|
234
238
|
private refuseIfPerson;
|
|
235
239
|
private takenOver;
|
|
236
240
|
private presenceUrls;
|
|
@@ -3,10 +3,12 @@ import { HarnessError } from '@deepseek-ai/dsh-llm';
|
|
|
3
3
|
import type { Session } from '@deepseek-ai/dsh-session';
|
|
4
4
|
import type { ToolRunContext } from '@deepseek-ai/dsh-tools';
|
|
5
5
|
import type { WriteTarget } from '../service/service.ts';
|
|
6
|
+
import { type BrowserCode } from '../types.ts';
|
|
6
7
|
/** dsh shows the model only the message, so the message starts with the code. */
|
|
7
8
|
export declare class BrowserToolError extends HarnessError {
|
|
9
|
+
readonly code: BrowserCode;
|
|
8
10
|
readonly reason: string;
|
|
9
|
-
constructor(code:
|
|
11
|
+
constructor(code: BrowserCode, reason: string);
|
|
10
12
|
}
|
|
11
13
|
export declare const NO_WORKSPACE_REASON = "this session has no working directory";
|
|
12
14
|
export interface ToolSession {
|
package/lib/types/types.d.ts
CHANGED
|
@@ -175,22 +175,25 @@ export interface TabInfo {
|
|
|
175
175
|
inPresence: boolean;
|
|
176
176
|
mayHaveChanged: boolean;
|
|
177
177
|
}
|
|
178
|
+
/** Every code this package reports. The values are the model-facing contract. */
|
|
179
|
+
export declare const BROWSER_CODES: readonly ["AUTHORITY_MISMATCH", "BROWSER_UNAVAILABLE", "INTERRUPTED", "INVALID_ARGS", "INVALID_INPUT", "ITEM_REFUSED", "MODAL_STATE", "NO_SESSION", "NO_WORKSPACE", "NOT_DECLARED", "NOT_DELIVERED", "OUTSIDE_WORKSPACE", "PERSON_IN_CONTROL", "SANDBOX_DENIED", "STALE_REF", "TAKEN_OVER", "UNKNOWN_TAB"];
|
|
180
|
+
export type BrowserCode = (typeof BROWSER_CODES)[number];
|
|
178
181
|
export declare class MhBrowserError extends Error {
|
|
179
|
-
readonly code:
|
|
182
|
+
readonly code: BrowserCode;
|
|
180
183
|
readonly page?: PageView;
|
|
181
|
-
constructor(code:
|
|
184
|
+
constructor(code: BrowserCode, message: string, page?: PageView);
|
|
182
185
|
}
|
|
183
186
|
/** Owner of the person's own window. It belongs to no Session. */
|
|
184
187
|
export declare const PERSON_OWNER = "person";
|
|
185
|
-
export declare const UNKNOWN_TAB
|
|
188
|
+
export declare const UNKNOWN_TAB: BrowserCode;
|
|
186
189
|
export declare const UNKNOWN_TAB_REASON = "no such tab in this session";
|
|
187
190
|
/**
|
|
188
191
|
* Internal: a wait ended because its signal aborted. A tool never reports it:
|
|
189
192
|
* a stopped call ends as the tool runtime's abort, a takeover as `TAKEN_OVER`.
|
|
190
193
|
*/
|
|
191
|
-
export declare const INTERRUPTED
|
|
194
|
+
export declare const INTERRUPTED: BrowserCode;
|
|
192
195
|
/** The browser did not start or could not be restarted. */
|
|
193
|
-
export declare const BROWSER_UNAVAILABLE
|
|
196
|
+
export declare const BROWSER_UNAVAILABLE: BrowserCode;
|
|
194
197
|
export declare function unknownTab(): PageError;
|
|
195
198
|
export type Download = {
|
|
196
199
|
kind: 'saved';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Shown on a session's tab group while a handover is waiting. */
|
|
2
|
+
export declare const WAITING_TITLE = "\u7B49\u4F60\uFF1A";
|
|
3
|
+
/** The question on the handover card. `reason` is the sentence the model gave. */
|
|
4
|
+
export declare function handoverQuestion(reason: string): string;
|
|
5
|
+
/** The option that hands the browser back. */
|
|
6
|
+
export declare const HAND_BACK = "\u4EA4\u56DE";
|
|
7
|
+
//# sourceMappingURL=words.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mind-harness/mh-browser",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Opens pages in a real browser for the agent, keeps chosen Agent Views in context, and hands the browser to you when a person is needed.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"files": [
|