@opengeni/runtime 3.1.3-canary.38890816741001 → 3.3.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/assets/codemode-client.json +1 -1
- package/dist/{chunk-462CH77G.js → chunk-EK7IW2FR.js} +177 -4
- package/dist/chunk-EK7IW2FR.js.map +1 -0
- package/dist/{chunk-GPCVTVNT.js → chunk-XRX57ZQO.js} +10 -6
- package/dist/{chunk-GPCVTVNT.js.map → chunk-XRX57ZQO.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/sandbox/browser-control-client.d.ts +10 -0
- package/dist/sandbox/browser-control-http.d.ts +33 -0
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/routing/backend-resolver.d.ts +1 -0
- package/dist/sandbox/selfhosted/session.d.ts +19 -0
- package/dist/workspace-tool-gateway.js +2 -2
- package/package.json +14 -14
- package/src/bundled_default_skills/opengeni-client/references/tools-and-auth.md +51 -0
- package/src/bundled_secret_skills/opengeni-secrets/SKILL.md +25 -24
- package/src/bundled_secret_skills/opengeni-secrets/references/troubleshooting.md +15 -0
- package/src/bundled_site_skills/opengeni-sites/SKILL.md +46 -12
- package/src/sandbox/browser-control-client.ts +89 -0
- package/src/sandbox/browser-control-http.ts +32 -0
- package/src/sandbox/routing/backend-resolver.ts +2 -0
- package/src/sandbox/selfhosted/session.ts +116 -0
- package/dist/chunk-462CH77G.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
workspaceEnvironmentInstructions,
|
|
188
188
|
wrapAttemptToolDefinitions,
|
|
189
189
|
wrapAttemptToolExecute
|
|
190
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-XRX57ZQO.js";
|
|
191
191
|
import {
|
|
192
192
|
ActiveBackendUnresolvableError,
|
|
193
193
|
BROWSER_CONTROL_ADMIN_TOKEN_FILE,
|
|
@@ -403,7 +403,7 @@ import {
|
|
|
403
403
|
withRunCredentialsSession,
|
|
404
404
|
withoutSandboxProviderIdentity,
|
|
405
405
|
workspaceArchiveDownloadTemporaryDirectory
|
|
406
|
-
} from "./chunk-
|
|
406
|
+
} from "./chunk-EK7IW2FR.js";
|
|
407
407
|
import {
|
|
408
408
|
SKILL_MAX_FILES,
|
|
409
409
|
SKILL_MAX_FILE_BYTES,
|
|
@@ -3,6 +3,7 @@ import { type BrowserFrameMetadata } from "@opengeni/sdk";
|
|
|
3
3
|
import { BROWSER_PROFILE_ARTIFACT_FORMAT, type BrowserActionCommand as BrowserActionCommandValue, type BrowserActionReceipt as BrowserActionReceiptValue, type BrowserClipboard as BrowserClipboardValue, type BrowserDiagnosticBatch as BrowserDiagnosticBatchValue, type BrowserDownload as BrowserDownloadValue, type BrowserDownloadExportReceipt as BrowserDownloadExportReceiptValue, type BrowserDownloadExportRequest as BrowserDownloadExportRequestValue, type BrowserDownloadListResponse as BrowserDownloadListResponseValue, type BrowserDomReadRequest as BrowserDomReadRequestValue, type BrowserDomReadResponse as BrowserDomReadResponseValue, type BrowserExternalAuthCommand as BrowserExternalAuthCommandValue, type BrowserExternalAuthResult as BrowserExternalAuthResultValue, type BrowserDiagnosticKind, type BrowserTargetListResponse as BrowserTargetListResponseValue, type BrowserObservation as BrowserObservationValue, type BrowserRevisionMaterialization as BrowserRevisionMaterializationValue, type BrowserTarget as BrowserTargetValue, type BrowserTargetState as BrowserTargetStateValue, type BrowserWorkspaceFileStageRequest as BrowserWorkspaceFileStageRequestValue, type BrowserWorkspaceFileStageResponse as BrowserWorkspaceFileStageResponseValue, type BrowserPasskeySyncRequest as BrowserPasskeySyncRequestValue, type BrowserPasskeySyncResponse as BrowserPasskeySyncResponseValue, type ComputerActionCommand as ComputerActionCommandValue, type ComputerActionReceipt as ComputerActionReceiptValue, type ComputerClipboard as ComputerClipboardValue, type ComputerObservation as ComputerObservationValue, type ComputerSessionCapabilities as ComputerSessionCapabilitiesValue, type ComputerTarget as ComputerTargetValue, type InteractionError as InteractionErrorValue, type NetworkRouteConsistency as NetworkRouteConsistencyValue } from "@opengeni/contracts";
|
|
4
4
|
import type { BrowserControlEnsureRequest, BrowserControlEnsureResponse, BrowserFramesOpenRequest, ComputerFramesOpenRequest, StreamChannel } from "@opengeni/agent-proto";
|
|
5
5
|
import { type EnsureBrowserControlServerResult } from "./browser-control-server.js";
|
|
6
|
+
import type { BrowserControlHttpCall, BrowserControlHttpOutcome } from "./browser-control-http.js";
|
|
6
7
|
import { type ExposedPortEndpoint } from "./stream-port.js";
|
|
7
8
|
export declare const BROWSER_CONTROL_ADMIN_TOKEN_FILE = "/tmp/opengeni-browserd/authority/admin-token";
|
|
8
9
|
type ExecResultLike = {
|
|
@@ -68,6 +69,8 @@ export type BrowserControlPlacementSession = {
|
|
|
68
69
|
}) => void;
|
|
69
70
|
};
|
|
70
71
|
ensureBrowserControl?: (request: BrowserControlEnsureRequest) => Promise<BrowserControlEnsureResponse>;
|
|
72
|
+
/** Agent-native controller transport, addressed by authority scope. */
|
|
73
|
+
browserControlHttp?: (request: BrowserControlHttpCall) => Promise<BrowserControlHttpOutcome>;
|
|
71
74
|
openBrowserFrames?: (request: BrowserFramesOpenRequest) => Promise<{
|
|
72
75
|
channel: StreamChannel;
|
|
73
76
|
endpoint: ExposedPortEndpoint;
|
|
@@ -434,6 +437,13 @@ export declare class BrowserControlClient {
|
|
|
434
437
|
private requestBytes;
|
|
435
438
|
private requestStream;
|
|
436
439
|
private controllerPort;
|
|
440
|
+
/** The agent-native transport: one in-process loopback request on the
|
|
441
|
+
* Connected Machine, addressed by authority scope, with no process started.
|
|
442
|
+
* Null when the placement does not serve it; the caller then keeps its
|
|
443
|
+
* command transport. A controller that is not running receives nothing, so
|
|
444
|
+
* it is ensured and the request sent once more whatever its method. */
|
|
445
|
+
private requestNative;
|
|
446
|
+
private ensureControllerPort;
|
|
437
447
|
}
|
|
438
448
|
export declare class BrowserControlSessionClient {
|
|
439
449
|
readonly reference: PlacementBrowserSessionReference;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** One request to an agent-owned browser/computer controller, addressed by its
|
|
2
|
+
* exact authority scope rather than a local port. */
|
|
3
|
+
export type BrowserControlHttpCall = {
|
|
4
|
+
scopeId: string;
|
|
5
|
+
scopeGeneration: string;
|
|
6
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
7
|
+
/** Absolute controller path with optional query. */
|
|
8
|
+
path: string;
|
|
9
|
+
bearerToken: string;
|
|
10
|
+
/** JSON request body bytes, when the request has a body. */
|
|
11
|
+
body?: Uint8Array;
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
maxResponseBytes: number;
|
|
14
|
+
};
|
|
15
|
+
/** What a placement transport did with one controller request. */
|
|
16
|
+
export type BrowserControlHttpOutcome =
|
|
17
|
+
/** The placement cannot serve it natively; nothing was sent. */
|
|
18
|
+
{
|
|
19
|
+
kind: "unsupported";
|
|
20
|
+
}
|
|
21
|
+
/** No controller for that scope and generation accepted it; nothing was
|
|
22
|
+
* delivered, so the caller may ensure the controller and send again. */
|
|
23
|
+
| {
|
|
24
|
+
kind: "controller_absent";
|
|
25
|
+
} | {
|
|
26
|
+
kind: "response";
|
|
27
|
+
status: number;
|
|
28
|
+
/** Lowercase header names. */
|
|
29
|
+
headers: Map<string, string>;
|
|
30
|
+
body: Uint8Array;
|
|
31
|
+
};
|
|
32
|
+
/** Extra time beyond the request's own deadline for the reply to arrive. */
|
|
33
|
+
export declare const BROWSER_CONTROL_HTTP_REPLY_GRACE_MS = 5000;
|
package/dist/sandbox/index.js
CHANGED
|
@@ -213,7 +213,7 @@ import {
|
|
|
213
213
|
withRunCredentialsSession,
|
|
214
214
|
withoutSandboxProviderIdentity,
|
|
215
215
|
workspaceArchiveDownloadTemporaryDirectory
|
|
216
|
-
} from "../chunk-
|
|
216
|
+
} from "../chunk-EK7IW2FR.js";
|
|
217
217
|
import "../chunk-5ULGMFKR.js";
|
|
218
218
|
import {
|
|
219
219
|
CODE_SEARCH_RG_MAX_BYTES,
|
|
@@ -32,6 +32,7 @@ export interface SelfhostedConnectionBinding {
|
|
|
32
32
|
operationResourcePolicySupported: boolean;
|
|
33
33
|
operationCpuQuotaSupported: boolean;
|
|
34
34
|
transactionalFsWriteSupported?: boolean;
|
|
35
|
+
browserControlHttpSupported?: boolean;
|
|
35
36
|
}
|
|
36
37
|
export interface ActiveBackendResolverDeps {
|
|
37
38
|
/** The workspace the session belongs to (the control-plane subject scope). */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ControlResponse, type BrowserControlEnsureRequest, type BrowserControlEnsureResponse, type BrowserFramesOpenRequest, type ComputerFramesOpenRequest, type StreamChannel } from "@opengeni/agent-proto";
|
|
2
2
|
import { Manifest } from "@openai/agents/sandbox";
|
|
3
3
|
import type { ExposedPortEndpoint } from "../stream-port.js";
|
|
4
|
+
import { type BrowserControlHttpCall, type BrowserControlHttpOutcome } from "../browser-control-http.js";
|
|
4
5
|
import { type ControlRpc } from "./control-rpc.js";
|
|
5
6
|
import { type SelfhostedRetryClock } from "./retry-policy.js";
|
|
6
7
|
import type { SelfhostedOpObserver } from "./op-observer.js";
|
|
@@ -100,6 +101,8 @@ export interface SelfhostedBackgroundCommandAdoption {
|
|
|
100
101
|
* every exec/Git admission; retries and already-started operations retain it. */
|
|
101
102
|
export interface SelfhostedOperationAdmission {
|
|
102
103
|
transactionalFsWriteSupported?: boolean;
|
|
104
|
+
/** The live runner serves in-process browser/computer controller requests. */
|
|
105
|
+
browserControlHttpSupported?: boolean;
|
|
103
106
|
/** Workspace segment of the physical agent/relay route. Personal machines may
|
|
104
107
|
* originate in a different same-organization workspace than the session. */
|
|
105
108
|
workspaceId?: string;
|
|
@@ -123,6 +126,9 @@ export interface SelfhostedOperationAdmission {
|
|
|
123
126
|
export interface SelfhostedSessionDeps {
|
|
124
127
|
/** Exact live daemon capability; absent preserves legacy small-file writes. */
|
|
125
128
|
transactionalFsWriteSupported?: boolean;
|
|
129
|
+
/** Exact live daemon capability; absent keeps controller requests on the
|
|
130
|
+
* command transport. */
|
|
131
|
+
browserControlHttpSupported?: boolean;
|
|
126
132
|
/** Authorization/session workspace. */
|
|
127
133
|
workspaceId: string;
|
|
128
134
|
/** Physical control-plane workspace. Defaults to workspaceId for legacy and
|
|
@@ -303,6 +309,7 @@ export declare class SelfhostedSession {
|
|
|
303
309
|
private readonly resourcePolicySupported;
|
|
304
310
|
private readonly operationCpuQuotaSupported;
|
|
305
311
|
private readonly transactionalFsWriteSupported;
|
|
312
|
+
private readonly browserControlHttpSupported;
|
|
306
313
|
private readonly defaultOpStream;
|
|
307
314
|
private readonly connectionInstanceId;
|
|
308
315
|
private readonly resolveOperationAdmission;
|
|
@@ -524,6 +531,14 @@ export declare class SelfhostedSession {
|
|
|
524
531
|
/** Ensure the loopback browser controller sidecar owned by this connected
|
|
525
532
|
* machine. The authority scope is supplied by the caller and remains local. */
|
|
526
533
|
ensureBrowserControl(request: BrowserControlEnsureRequest): Promise<BrowserControlEnsureResponse>;
|
|
534
|
+
/** Send one request to the agent-owned controller of an exact authority
|
|
535
|
+
* scope, served inside the runner over loopback without starting a process.
|
|
536
|
+
* `unsupported` means this connection's runner does not serve it and nothing
|
|
537
|
+
* was sent. `controller_absent` means no controller for that scope and
|
|
538
|
+
* generation accepted the request, so it was not delivered and the caller may
|
|
539
|
+
* ensure the controller and send again. A body too large for one reply is
|
|
540
|
+
* drained from the runner's spool; the request is never repeated. */
|
|
541
|
+
browserControlHttp(request: BrowserControlHttpCall): Promise<BrowserControlHttpOutcome>;
|
|
527
542
|
/** Open one browser-native frame producer and return its canonical relay
|
|
528
543
|
* endpoint. This does not route through `resolveExposedPort`: that legacy
|
|
529
544
|
* method allocates PTY/desktop resources based on fixed ports, while this op
|
|
@@ -597,6 +612,7 @@ export declare class SelfhostedSandboxClient {
|
|
|
597
612
|
private readonly operationResourcePolicySupported;
|
|
598
613
|
private readonly operationCpuQuotaSupported;
|
|
599
614
|
private readonly transactionalFsWriteSupported;
|
|
615
|
+
private readonly browserControlHttpSupported;
|
|
600
616
|
private readonly resolveOperationAdmission;
|
|
601
617
|
private readonly adoptBackgroundCommand;
|
|
602
618
|
private readonly settleBackgroundCommand;
|
|
@@ -631,6 +647,7 @@ export declare class SelfhostedSandboxClient {
|
|
|
631
647
|
operationResourcePolicySupported?: boolean;
|
|
632
648
|
operationCpuQuotaSupported?: boolean;
|
|
633
649
|
transactionalFsWriteSupported?: boolean;
|
|
650
|
+
browserControlHttpSupported?: boolean;
|
|
634
651
|
resolveOperationAdmission?: () => Promise<SelfhostedOperationAdmission | null>;
|
|
635
652
|
adoptBackgroundCommand?: SelfhostedSessionDeps["adoptBackgroundCommand"];
|
|
636
653
|
settleBackgroundCommand?: SelfhostedSessionDeps["settleBackgroundCommand"];
|
|
@@ -711,6 +728,8 @@ export interface SelfhostedSessionBuild {
|
|
|
711
728
|
/** Exact live CPU enforcement capability paired with the initial snapshot. */
|
|
712
729
|
operationCpuQuotaSupported?: boolean;
|
|
713
730
|
transactionalFsWriteSupported?: boolean;
|
|
731
|
+
/** Exact live runner capability for in-process controller requests. */
|
|
732
|
+
browserControlHttpSupported?: boolean;
|
|
714
733
|
/** Live last-boundary operation admission resolver; see SelfhostedSessionDeps. */
|
|
715
734
|
resolveOperationAdmission?: () => Promise<SelfhostedOperationAdmission | null>;
|
|
716
735
|
adoptBackgroundCommand?: SelfhostedSessionDeps["adoptBackgroundCommand"];
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
prepareAgentTools,
|
|
4
4
|
secretArgumentMode,
|
|
5
5
|
sessionMcpApprovalConnectionId
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-XRX57ZQO.js";
|
|
7
|
+
import "./chunk-EK7IW2FR.js";
|
|
8
8
|
import "./chunk-4KFT2G3W.js";
|
|
9
9
|
import "./chunk-7OUG7WBV.js";
|
|
10
10
|
import "./chunk-5ULGMFKR.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -75,19 +75,19 @@
|
|
|
75
75
|
"@openai/agents": "0.14.3",
|
|
76
76
|
"@openai/agents-core": "0.14.3",
|
|
77
77
|
"@openai/agents-extensions": "0.14.3",
|
|
78
|
-
"@opengeni/agent-proto": "3.
|
|
79
|
-
"@opengeni/capabilities": "3.
|
|
80
|
-
"@opengeni/codemode": "3.
|
|
81
|
-
"@opengeni/codex": "3.
|
|
82
|
-
"@opengeni/config": "3.
|
|
83
|
-
"@opengeni/contracts": "3.
|
|
84
|
-
"@opengeni/interaction": "3.
|
|
85
|
-
"@opengeni/network": "3.
|
|
86
|
-
"@opengeni/observability": "3.
|
|
87
|
-
"@opengeni/sdk": "3.
|
|
88
|
-
"@opengeni/tool-gateway": "3.
|
|
89
|
-
"@opengeni/vaults": "3.
|
|
90
|
-
"@opengeni/xai-subscription": "3.
|
|
78
|
+
"@opengeni/agent-proto": "3.3.0",
|
|
79
|
+
"@opengeni/capabilities": "3.3.0",
|
|
80
|
+
"@opengeni/codemode": "3.3.0",
|
|
81
|
+
"@opengeni/codex": "3.3.0",
|
|
82
|
+
"@opengeni/config": "3.3.0",
|
|
83
|
+
"@opengeni/contracts": "3.3.0",
|
|
84
|
+
"@opengeni/interaction": "3.3.0",
|
|
85
|
+
"@opengeni/network": "3.3.0",
|
|
86
|
+
"@opengeni/observability": "3.3.0",
|
|
87
|
+
"@opengeni/sdk": "3.3.0",
|
|
88
|
+
"@opengeni/tool-gateway": "3.3.0",
|
|
89
|
+
"@opengeni/vaults": "3.3.0",
|
|
90
|
+
"@opengeni/xai-subscription": "3.3.0",
|
|
91
91
|
"debug": "4.4.3",
|
|
92
92
|
"modal": "0.9.0",
|
|
93
93
|
"openai": "6.47.0",
|
|
@@ -193,3 +193,54 @@ README's Workspace tools section for approval and migration details.
|
|
|
193
193
|
Never put tokens in prompts, Skills, `modelContext`, tool URLs, browser code,
|
|
194
194
|
or logs. Opengeni stores Connection and MCP header secrets encrypted and keeps
|
|
195
195
|
them out of the model's context.
|
|
196
|
+
|
|
197
|
+
### Your product as a vault provider
|
|
198
|
+
|
|
199
|
+
Use native vaults when the agent needs to discover and use stored credentials.
|
|
200
|
+
An embedding product can expose multiple remote vaults through a signed
|
|
201
|
+
`external` connection; an in-process host can keep using
|
|
202
|
+
`connectionCredentials.vaultProvider`. Keep the simple chat/tool integration
|
|
203
|
+
above unchanged unless the product actually needs this optional capability.
|
|
204
|
+
|
|
205
|
+
Configure remote connections on the server with `vaultsApi(client, workspaceId)`
|
|
206
|
+
from `@opengeni/sdk`: `installVaultProvider`, `getVaultProviderCatalog`,
|
|
207
|
+
`listProviderVaults`, and `linkProviderVault`. Never put provider tokens or the
|
|
208
|
+
signing secret in browser code, model context, or URL parameters. Verify each
|
|
209
|
+
request's raw-body signature and map its native account/workspace/subject to
|
|
210
|
+
the host's actual tenant/user before authorizing it. A shared connection must
|
|
211
|
+
not return a different user's inventory into the same metadata mirror; use
|
|
212
|
+
separate user-owned connections for user-specific stores.
|
|
213
|
+
|
|
214
|
+
Connection setup uses the existing `connections:write` and `secrets:write`
|
|
215
|
+
permissions and native owner checks, including authorized agent attempts for
|
|
216
|
+
shared connections. Personal setup requires the verified owner, and
|
|
217
|
+
organization setup requires its admin. List/read/write operations always use
|
|
218
|
+
the registered connection endpoint, not a per-call URL chosen by a tool caller.
|
|
219
|
+
|
|
220
|
+
`getVaultProviderCatalog` includes deployment availability even before anyone
|
|
221
|
+
connects; disable unavailable setup choices instead of collecting credentials
|
|
222
|
+
that this deployment cannot use. `listVaultProviderConnections` remains a
|
|
223
|
+
metadata-only convenience when only existing connections are needed.
|
|
224
|
+
|
|
225
|
+
For a remote host, use `createExternalVaultReceiver` from the server-only
|
|
226
|
+
`@opengeni/sdk/external-vault-receiver` subpath and a durable atomic replay and
|
|
227
|
+
mutation store. The in-memory store is only for local tests. Its
|
|
228
|
+
`resolveConnection` binds the native connection to one fixed host inventory;
|
|
229
|
+
`authorize` checks the mapped person on every operation. If the host must
|
|
230
|
+
register the native connection ID first, install returns saved/pending setup;
|
|
231
|
+
register that ID, then verify. Never accept all unknown connections into one
|
|
232
|
+
default tenant to avoid this registration step.
|
|
233
|
+
|
|
234
|
+
Provider capabilities are granular: do not assume every read-write vault can
|
|
235
|
+
update TOTP, upload files, restore history or archive items. Distinguish cached
|
|
236
|
+
metadata from live value reads. Incomplete discovery or an unavailable source
|
|
237
|
+
is not proof that the user has no matching secret. For a saved-but-pending
|
|
238
|
+
setup (`discoveryPending: true`), use `verifyVaultProviderConnection` with the
|
|
239
|
+
connection ID rather than resubmitting a consumed bootstrap token.
|
|
240
|
+
|
|
241
|
+
The native secret ask card still saves to hosted vaults only. If the host must
|
|
242
|
+
own collection, collect in the host UI and expose the saved item via its
|
|
243
|
+
provider. Keep short-lived per-attempt credentials on the existing renewable
|
|
244
|
+
credential callback: a stored item does not replace expiry/renewal, Git/MCP
|
|
245
|
+
transport bindings or cleanup. See the product's external-vault and credential
|
|
246
|
+
provider documentation before implementing either path.
|
|
@@ -5,10 +5,8 @@ description: Use when signing in, creating accounts, storing or using passwords,
|
|
|
5
5
|
|
|
6
6
|
# Secrets: sign in and use credentials yourself
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
codes, and solve CAPTCHAs. You never need to see a value: write a reference and
|
|
11
|
-
it resolves where it runs.
|
|
8
|
+
Use references instead of viewing values. Sign in, create accounts when the
|
|
9
|
+
task allows it, enroll 2FA, fetch codes and solve CAPTCHAs yourself.
|
|
12
10
|
|
|
13
11
|
## References
|
|
14
12
|
|
|
@@ -30,16 +28,15 @@ The `secret_*` tools take references as names and never resolve them.
|
|
|
30
28
|
|
|
31
29
|
## Tools
|
|
32
30
|
|
|
33
|
-
- `secret_search
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`restoreVersion`.
|
|
39
|
-
- `secret_move
|
|
40
|
-
- `secret_delete
|
|
41
|
-
- `secret_get
|
|
42
|
-
when a tool cannot take a reference.
|
|
31
|
+
- `secret_search`: metadata and references, never values. No filters lists all;
|
|
32
|
+
page one lists vaults. Follow `nextCursor` with unchanged filters. Check
|
|
33
|
+
`complete` and freshness before inferring absence. `refresh: true` requests
|
|
34
|
+
fresh inventory without bypassing rate limits.
|
|
35
|
+
- `secret_save`: each field takes `value`, `generate`, `fromReference` or
|
|
36
|
+
`restoreVersion`. Generate new passwords.
|
|
37
|
+
- `secret_move`: move or copy to another vault.
|
|
38
|
+
- `secret_delete`: archive an item.
|
|
39
|
+
- `secret_get`: plaintext with `secrets:read`, only if references cannot work.
|
|
43
40
|
|
|
44
41
|
## Login ladder
|
|
45
42
|
|
|
@@ -65,9 +62,9 @@ after one failure.
|
|
|
65
62
|
|
|
66
63
|
- `saveTo`: `user` (Only me, reused later), `task` (throwaway, shared with this
|
|
67
64
|
task's sessions) or `workspace` (team keys, schedules that run without you).
|
|
68
|
-
- Name items
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
- Name items by service/account; record `websites` and `username`.
|
|
66
|
+
- Respect provider capabilities. Ask cards save to hosted vaults only.
|
|
67
|
+
Provider write and move limits: `references/troubleshooting.md`.
|
|
71
68
|
|
|
72
69
|
## Missing secrets and errors
|
|
73
70
|
|
|
@@ -75,12 +72,16 @@ A tool result with `secret_reference_error` ran nothing. For a missing secret
|
|
|
75
72
|
it includes `askCard`: call `request_human_input` with it, changing only
|
|
76
73
|
`saveTo` or `prompt`, then retry with the returned reference.
|
|
77
74
|
|
|
75
|
+
An unavailable or incomplete provider is not a missing secret: respect retry
|
|
76
|
+
times or reconnect/unlock it. Inspect unknown write outcomes before retrying;
|
|
77
|
+
never repeat a create just because its inventory refresh failed.
|
|
78
|
+
|
|
78
79
|
## Playbooks
|
|
79
80
|
|
|
80
|
-
- `references/login-playbook.md
|
|
81
|
-
- `references/account-creation.md
|
|
82
|
-
- `references/2fa-enrollment.md
|
|
83
|
-
- `references/api-keys.md
|
|
84
|
-
- `references/ask-card.md
|
|
85
|
-
- `references/troubleshooting.md
|
|
86
|
-
- `references/codemode-and-scripts.md
|
|
81
|
+
- Login: `references/login-playbook.md`.
|
|
82
|
+
- Sign-up: `references/account-creation.md`.
|
|
83
|
+
- TOTP: `references/2fa-enrollment.md`.
|
|
84
|
+
- CLI/files: `references/api-keys.md`.
|
|
85
|
+
- Secret card: `references/ask-card.md`.
|
|
86
|
+
- Errors: `references/troubleshooting.md`.
|
|
87
|
+
- Escaping: `references/codemode-and-scripts.md`.
|
|
@@ -23,6 +23,21 @@ and a `hint`. Fix the reference and retry the same action.
|
|
|
23
23
|
|
|
24
24
|
## Save and vault errors
|
|
25
25
|
|
|
26
|
+
Connected providers advertise their supported operations. Do not work around a
|
|
27
|
+
read-only or unsupported operation by exposing values in logs or process
|
|
28
|
+
arguments. A move requires recoverable removal at the source; a copy may still
|
|
29
|
+
be supported without it. Ask cards save to hosted vaults only.
|
|
30
|
+
|
|
31
|
+
An offline, locked, rate-limited or incomplete source is not proof that a secret
|
|
32
|
+
is missing. Check search `complete` and source freshness, preserve filters while
|
|
33
|
+
paging, and request `refresh: true` deliberately. It respects rate limits. Report
|
|
34
|
+
the reconnect or unlock action rather than asking for the secret again.
|
|
35
|
+
|
|
36
|
+
For `provider_outcome_unknown`, inspect the provider before retrying: a write
|
|
37
|
+
may already have succeeded. `provider_inventory_incomplete` with `saved: true`
|
|
38
|
+
means the write succeeded but the subsequent inventory refresh failed. Refresh
|
|
39
|
+
the inventory; never automatically repeat the create.
|
|
40
|
+
|
|
26
41
|
| Error | What to do |
|
|
27
42
|
|---|---|
|
|
28
43
|
| `vault_read_only` | A connected vault is read-only. Save to an Opengeni vault (`saveTo` without `vault`) or ask the user to make it writable. |
|
|
@@ -18,8 +18,9 @@ Site on the web is built in (see "Publish to the web").
|
|
|
18
18
|
|
|
19
19
|
A Site never needs its own server, API key, or hosting provider to reach
|
|
20
20
|
Opengeni. Model access, agent conversations, and workspace tools all come from
|
|
21
|
-
the host bridge: `createOpenGeniSiteClient` from `@opengeni/sdk/site
|
|
22
|
-
`@opengeni/react/session-ui`
|
|
21
|
+
the host bridge: `createOpenGeniSiteClient` from `@opengeni/sdk/site`. Use its
|
|
22
|
+
`ai.run` helper for inline results, or `@opengeni/react/session-ui` when the app
|
|
23
|
+
needs a conversation surface. The parent page owns the
|
|
23
24
|
credentials and workspace identity; Site code receives neither, so "keep
|
|
24
25
|
credentials server-side" is already satisfied by that bridge.
|
|
25
26
|
|
|
@@ -239,6 +240,33 @@ const client = createOpenGeniSiteClient();
|
|
|
239
240
|
const issues = await client.tools.linear.issues_list({ state: "Todo" });
|
|
240
241
|
```
|
|
241
242
|
|
|
243
|
+
### Inline AI: the app chooses the interaction
|
|
244
|
+
|
|
245
|
+
Use `site.ai.run({ initialMessage: appDefinedPrompt, idempotencyKey: actionId })`
|
|
246
|
+
to return AI output inside the app without mounting chat or displaying history.
|
|
247
|
+
Prompts, context, controls and results are app-designed; Draft, Summarize or
|
|
248
|
+
Classify are merely possible examples, never required buttons or templates.
|
|
249
|
+
Use `onText` for incremental text and `onSession` to retain a native handle before
|
|
250
|
+
waiting. A result has `text`, `sessionId`, `turnId`, `after` and `status`:
|
|
251
|
+
`completed`, `pending` (approval/input needed), or `cancelled`; failures reject.
|
|
252
|
+
Validate any app-defined structured output before using it.
|
|
253
|
+
|
|
254
|
+
This is ordinary native execution with the same model access, subscriptions,
|
|
255
|
+
permissions, tool selection, approvals, metering and outsider caps. Aborting the
|
|
256
|
+
observation does not cancel the task. `site.ai.result(id, { turnId })` replays
|
|
257
|
+
without creating more work. Supplying `after` returns subsequent text only;
|
|
258
|
+
retain earlier text or omit it for a full replay. Keep retry keys stable per
|
|
259
|
+
action and handles in viewer-private state/storage, not shared Site Data.
|
|
260
|
+
|
|
261
|
+
Site AI is private per viewer by default and does not clutter the workspace
|
|
262
|
+
sidebar or ordinary search. Signed-in members use their real human identity;
|
|
263
|
+
guests use existing cookie/visitor continuity, not a shared anonymous chat.
|
|
264
|
+
If organization policy disallows private execution, surface its explicit
|
|
265
|
+
refusal; never fall back to shared sessions. Privacy does not automatically
|
|
266
|
+
extend to separately published artifacts or shared Site Data.
|
|
267
|
+
|
|
268
|
+
### Optional conversation UI
|
|
269
|
+
|
|
242
270
|
For embedded conversations, `site.client` is the ordinary Opengeni SDK client;
|
|
243
271
|
`site.workspaceId` is a host-resolved routing alias. Use the normal React
|
|
244
272
|
complete conversation surface—do not implement session REST or SSE yourself:
|
|
@@ -259,7 +287,7 @@ const site = createOpenGeniSiteClient();
|
|
|
259
287
|
```
|
|
260
288
|
|
|
261
289
|
`sessionId` is the existing session or the id returned by `site.client.createSession`.
|
|
262
|
-
For a normal chat app,
|
|
290
|
+
For a normal chat app, a conversation selector and “New conversation” are optional.
|
|
263
291
|
Create on first Send rather than mounting the page; keep the selected id in React
|
|
264
292
|
state and reopen existing conversations through the SDK.
|
|
265
293
|
Keep first-send creation single-flight; reuse its `idempotencyKey` when retrying,
|
|
@@ -272,14 +300,17 @@ write origin metadata yourself. The local preview has no published identity, so
|
|
|
272
300
|
this filter returns no Site history there; test newly created/current conversations
|
|
273
301
|
locally and the selector after publication.
|
|
274
302
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
303
|
+
Do not automatically create a project just to group Site chats. Site execution
|
|
304
|
+
does not appear in ordinary workspace discovery, even for its owner. The host
|
|
305
|
+
Site page provides a viewer-scoped Conversations panel independently of app
|
|
306
|
+
navigation. Opening existing sessions never changes their origin or audience.
|
|
307
|
+
Page code cannot widen the Site boundary by supplying project, visibility,
|
|
308
|
+
tools or credential fields; use ordinary authoring tools for project management.
|
|
309
|
+
|
|
310
|
+
Per-Site AI costs are in Insights: actual credit charges are distinct from
|
|
311
|
+
API-equivalent subscription/own-key estimates and unbilled platform counters.
|
|
312
|
+
Usage is for limits. Do not build private transcript or viewer analytics into
|
|
313
|
+
shared dashboards just because aggregate costs are visible there.
|
|
283
314
|
|
|
284
315
|
`SessionConversation` connects timeline/history, durable composer drafts,
|
|
285
316
|
queue display/edit/delete/steer, pause/resume, and human-input forms. Prefer it
|
|
@@ -667,8 +698,11 @@ workspace first.
|
|
|
667
698
|
`rate_limited`, `site_budget_exhausted` and retryable `site_budget_busy` (429), and
|
|
668
699
|
`site_platform_brake_engaged` (503) as normal UI states.
|
|
669
700
|
- The same Site HTML and Site Data work there; no rebuild is needed.
|
|
670
|
-
-
|
|
701
|
+
- Published-host agents get this Site's `site_data_query` and `site_data_write`,
|
|
671
702
|
plus `site_sql_run` when SQL is enabled; members also get read-only `site_sql_query`.
|
|
703
|
+
Member tools are intersected with live permissions: a member without artifact
|
|
704
|
+
publishing can still use AI without write tools, and without data-read permission
|
|
705
|
+
can use plain AI without data tools. Never request extra permission just to chat.
|
|
672
706
|
The server pins the Site and binds calls to the conversation's viewer, including
|
|
673
707
|
collection ownership and query audiences. No management tools or sandbox are
|
|
674
708
|
supplied; publication settings have no sandbox opt-in. Members get no Site
|
|
@@ -87,6 +87,7 @@ import {
|
|
|
87
87
|
} from "./browser-control-server";
|
|
88
88
|
import { parseExecResponseBanner } from "./exec-banner";
|
|
89
89
|
import { controllerStreamRequest, parseControllerStreamResponse } from "./browser-control-stream";
|
|
90
|
+
import type { BrowserControlHttpCall, BrowserControlHttpOutcome } from "./browser-control-http";
|
|
90
91
|
import {
|
|
91
92
|
buildStreamUrl,
|
|
92
93
|
exposedPortAllowsHostFetch,
|
|
@@ -177,6 +178,8 @@ export type BrowserControlPlacementSession = {
|
|
|
177
178
|
ensureBrowserControl?: (
|
|
178
179
|
request: BrowserControlEnsureRequest,
|
|
179
180
|
) => Promise<BrowserControlEnsureResponse>;
|
|
181
|
+
/** Agent-native controller transport, addressed by authority scope. */
|
|
182
|
+
browserControlHttp?: (request: BrowserControlHttpCall) => Promise<BrowserControlHttpOutcome>;
|
|
180
183
|
openBrowserFrames?: (
|
|
181
184
|
request: BrowserFramesOpenRequest,
|
|
182
185
|
) => Promise<{ channel: StreamChannel; endpoint: ExposedPortEndpoint }>;
|
|
@@ -1176,6 +1179,19 @@ export class BrowserControlClient {
|
|
|
1176
1179
|
);
|
|
1177
1180
|
}
|
|
1178
1181
|
|
|
1182
|
+
const native = await this.requestNative(input, BROWSER_CONTROL_MAX_JSON_BYTES);
|
|
1183
|
+
if (native) {
|
|
1184
|
+
let text: string;
|
|
1185
|
+
try {
|
|
1186
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(native.body);
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
throw new BrowserControlProtocolError("browser controller response is not UTF-8", {
|
|
1189
|
+
cause: error,
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
return parseEnvelope(text, native.status);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1179
1195
|
if (
|
|
1180
1196
|
this.session.execWithInput &&
|
|
1181
1197
|
(input.body === undefined || Buffer.byteLength(JSON.stringify(input.body)) <= 32 * 1024)
|
|
@@ -1357,6 +1373,18 @@ export class BrowserControlClient {
|
|
|
1357
1373
|
);
|
|
1358
1374
|
}
|
|
1359
1375
|
|
|
1376
|
+
const nativeFrame = await this.requestNative(
|
|
1377
|
+
input,
|
|
1378
|
+
input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES,
|
|
1379
|
+
);
|
|
1380
|
+
if (nativeFrame) {
|
|
1381
|
+
if (nativeFrame.status < 200 || nativeFrame.status >= 300) {
|
|
1382
|
+
parseEnvelope(new TextDecoder().decode(nativeFrame.body), nativeFrame.status);
|
|
1383
|
+
throw new BrowserControlProtocolError("browser controller image response is invalid");
|
|
1384
|
+
}
|
|
1385
|
+
return controllerImageFrame(nativeFrame.body, nativeFrame.headers, input);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1360
1388
|
if (this.session.execWithInput) {
|
|
1361
1389
|
try {
|
|
1362
1390
|
const response = await this.requestStream(
|
|
@@ -1512,8 +1540,69 @@ export class BrowserControlClient {
|
|
|
1512
1540
|
}
|
|
1513
1541
|
|
|
1514
1542
|
private async controllerPort(): Promise<number> {
|
|
1543
|
+
if (!this.nativeAuthority || !this.session.ensureBrowserControl) return this.port;
|
|
1544
|
+
return await this.ensureControllerPort(false);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
/** The agent-native transport: one in-process loopback request on the
|
|
1548
|
+
* Connected Machine, addressed by authority scope, with no process started.
|
|
1549
|
+
* Null when the placement does not serve it; the caller then keeps its
|
|
1550
|
+
* command transport. A controller that is not running receives nothing, so
|
|
1551
|
+
* it is ensured and the request sent once more whatever its method. */
|
|
1552
|
+
private async requestNative(
|
|
1553
|
+
input: { method: string; path: string; token: string; body?: unknown; timeoutMs?: number },
|
|
1554
|
+
maxResponseBytes: number,
|
|
1555
|
+
retry = true,
|
|
1556
|
+
): Promise<{ status: number; headers: Map<string, string>; body: Uint8Array } | null> {
|
|
1557
|
+
const authority = this.nativeAuthority;
|
|
1558
|
+
if (!authority || !this.session.browserControlHttp || !this.session.ensureBrowserControl) {
|
|
1559
|
+
return null;
|
|
1560
|
+
}
|
|
1561
|
+
const method = input.method;
|
|
1562
|
+
if (method !== "GET" && method !== "POST" && method !== "PUT" && method !== "DELETE") {
|
|
1563
|
+
throw new BrowserControlProtocolError("browser controller request method is invalid");
|
|
1564
|
+
}
|
|
1565
|
+
// Validates the path exactly as the command transport does.
|
|
1566
|
+
localControllerUrl(this.port, input.path);
|
|
1567
|
+
const body =
|
|
1568
|
+
input.body === undefined ? undefined : new TextEncoder().encode(JSON.stringify(input.body));
|
|
1569
|
+
if (body !== undefined && body.byteLength > BROWSER_CONTROL_MAX_JSON_BYTES) {
|
|
1570
|
+
throw new RangeError("browser controller request body is too large");
|
|
1571
|
+
}
|
|
1572
|
+
let outcome: BrowserControlHttpOutcome;
|
|
1573
|
+
try {
|
|
1574
|
+
outcome = await this.session.browserControlHttp({
|
|
1575
|
+
scopeId: authority.scopeId,
|
|
1576
|
+
scopeGeneration: authority.scopeGeneration,
|
|
1577
|
+
method,
|
|
1578
|
+
path: input.path,
|
|
1579
|
+
bearerToken: requireToken(input.token, "browser controller token"),
|
|
1580
|
+
...(body === undefined ? {} : { body }),
|
|
1581
|
+
timeoutMs: boundedTimeout(input.timeoutMs ?? this.timeoutMs),
|
|
1582
|
+
maxResponseBytes,
|
|
1583
|
+
});
|
|
1584
|
+
} catch (error) {
|
|
1585
|
+
if (retry && method === "GET") {
|
|
1586
|
+
await this.ensureControllerPort(true);
|
|
1587
|
+
return await this.requestNative(input, maxResponseBytes, false);
|
|
1588
|
+
}
|
|
1589
|
+
throw new BrowserControlTransportError("browser controller request transport failed", {
|
|
1590
|
+
cause: error,
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
if (outcome.kind === "unsupported") return null;
|
|
1594
|
+
if (outcome.kind === "controller_absent") {
|
|
1595
|
+
if (!retry) throw new BrowserControlTransportError("browser controller is not running");
|
|
1596
|
+
await this.ensureControllerPort(true);
|
|
1597
|
+
return await this.requestNative(input, maxResponseBytes, false);
|
|
1598
|
+
}
|
|
1599
|
+
return outcome;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
private async ensureControllerPort(replace: boolean): Promise<number> {
|
|
1515
1603
|
if (!this.nativeAuthority || !this.session.ensureBrowserControl) return this.port;
|
|
1516
1604
|
const key = nativeControllerKey(this.nativeAuthority);
|
|
1605
|
+
if (replace) nativeControllerPorts.delete(key);
|
|
1517
1606
|
const cached = nativeControllerPorts.get(key);
|
|
1518
1607
|
if (cached !== undefined) return cached;
|
|
1519
1608
|
const ensured = await this.session.ensureBrowserControl({
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** One request to an agent-owned browser/computer controller, addressed by its
|
|
2
|
+
* exact authority scope rather than a local port. */
|
|
3
|
+
export type BrowserControlHttpCall = {
|
|
4
|
+
scopeId: string;
|
|
5
|
+
scopeGeneration: string;
|
|
6
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
7
|
+
/** Absolute controller path with optional query. */
|
|
8
|
+
path: string;
|
|
9
|
+
bearerToken: string;
|
|
10
|
+
/** JSON request body bytes, when the request has a body. */
|
|
11
|
+
body?: Uint8Array;
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
maxResponseBytes: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** What a placement transport did with one controller request. */
|
|
17
|
+
export type BrowserControlHttpOutcome =
|
|
18
|
+
/** The placement cannot serve it natively; nothing was sent. */
|
|
19
|
+
| { kind: "unsupported" }
|
|
20
|
+
/** No controller for that scope and generation accepted it; nothing was
|
|
21
|
+
* delivered, so the caller may ensure the controller and send again. */
|
|
22
|
+
| { kind: "controller_absent" }
|
|
23
|
+
| {
|
|
24
|
+
kind: "response";
|
|
25
|
+
status: number;
|
|
26
|
+
/** Lowercase header names. */
|
|
27
|
+
headers: Map<string, string>;
|
|
28
|
+
body: Uint8Array;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Extra time beyond the request's own deadline for the reply to arrive. */
|
|
32
|
+
export const BROWSER_CONTROL_HTTP_REPLY_GRACE_MS = 5_000;
|