@opengeni/runtime 4.6.0 → 4.7.0-canary.37090756480001
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-instructions/modules/media.d.ts +3 -0
- package/dist/anthropic-messages.d.ts +13 -3
- package/dist/anthropic-request-error.d.ts +10 -0
- package/dist/assets/codemode-client.json +1 -1
- package/dist/{chunk-A22BKN4P.js → chunk-LJNCGUMB.js} +3 -3
- package/dist/chunk-LJNCGUMB.js.map +1 -0
- package/dist/{chunk-GTWKWJ67.js → chunk-P2OVGKDG.js} +505 -100
- package/dist/chunk-P2OVGKDG.js.map +1 -0
- package/dist/{chunk-D5DPVA2C.js → chunk-R25L27T3.js} +2047 -1275
- package/dist/chunk-R25L27T3.js.map +1 -0
- package/dist/claude-subscription-usage.d.ts +14 -4
- package/dist/context-compaction.d.ts +7 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -3
- package/dist/interaction-tools.d.ts +1 -1
- package/dist/mcp-network.js +1 -1
- package/dist/runtime-skills.d.ts +1 -0
- package/dist/sandbox/channel-a.d.ts +3 -0
- package/dist/sandbox/index.d.ts +3 -1
- package/dist/sandbox/index.js +7 -1
- package/dist/sandbox/provider-command-session.d.ts +21 -0
- package/dist/sandbox/providers/modal-command-argv.d.ts +4 -0
- package/dist/sandbox/providers/modal-command-control.d.ts +17 -5
- package/dist/sandbox/providers/modal-command-observation-errors.d.ts +3 -0
- package/dist/sandbox/providers/modal-command-raw-page.d.ts +100 -0
- package/dist/sandbox/providers/modal-command-router-wire.d.ts +17 -0
- package/dist/sandbox/routing/routing-session.d.ts +10 -0
- package/dist/sandbox/turn-tool-cancellation.d.ts +4 -0
- package/dist/workspace-tool-gateway.js +3 -3
- package/package.json +12 -12
- package/src/agent-instructions/PROMPT_CHANGELOG.md +23 -1
- package/src/agent-instructions/compose.ts +2 -0
- package/src/agent-instructions/modules/media.ts +20 -0
- package/src/agent-instructions/runtime-mechanics.ts +8 -0
- package/src/anthropic-messages.ts +223 -31
- package/src/anthropic-request-error.ts +45 -0
- package/src/bundled_default_skills/opengeni-client/SKILL.md +9 -7
- package/src/bundled_default_skills/opengeni-client/references/agent-recipes.md +1 -1
- package/src/bundled_default_skills/opengeni-client/references/api-workflows.md +61 -0
- package/src/bundled_default_skills/opengeni-client/references/compatibility-and-troubleshooting.md +86 -0
- package/src/bundled_default_skills/opengeni-client/references/data-tools-and-credentials.md +82 -0
- package/src/bundled_default_skills/opengeni-client/references/discovery-and-autonomy.md +32 -25
- package/src/bundled_default_skills/opengeni-client/references/external-users-and-connect.md +17 -0
- package/src/bundled_default_skills/opengeni-client/references/product-shapes-and-ui.md +156 -0
- package/src/bundled_schedule_skills/opengeni-schedules/SKILL.md +56 -0
- package/src/claude-subscription-usage.ts +55 -9
- package/src/context-compaction.ts +16 -9
- package/src/index.ts +85 -18
- package/src/interaction-tools.ts +113 -3
- package/src/lazy-tool-transport.ts +26 -10
- package/src/mcp-network.ts +4 -2
- package/src/model-provider-client.ts +11 -3
- package/src/model-provider-routing.ts +4 -0
- package/src/runtime-skills.ts +8 -0
- package/src/sandbox/channel-a.ts +3 -0
- package/src/sandbox/index.ts +11 -1
- package/src/sandbox/provider-command-session.ts +58 -0
- package/src/sandbox/provider-errors.ts +43 -9
- package/src/sandbox/providers/modal-command-argv.ts +20 -0
- package/src/sandbox/providers/modal-command-control.ts +422 -116
- package/src/sandbox/providers/modal-command-observation-errors.ts +65 -0
- package/src/sandbox/providers/modal-command-raw-page.ts +147 -0
- package/src/sandbox/providers/modal-command-router-wire.ts +104 -12
- package/src/sandbox/providers/modal-command-session.ts +26 -4
- package/src/sandbox/providers/modal-legacy-command-control.ts +2 -9
- package/src/sandbox/providers/modal-materialization-verification.ts +70 -6
- package/src/sandbox/routing/routing-session.ts +140 -41
- package/src/sandbox/run-credentials.ts +62 -19
- package/src/sandbox/turn-tool-cancellation.ts +159 -42
- package/dist/chunk-A22BKN4P.js.map +0 -1
- package/dist/chunk-D5DPVA2C.js.map +0 -1
- package/dist/chunk-GTWKWJ67.js.map +0 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The checkpoint model sees the current active history plus one fixed
|
|
5
5
|
* checkpoint prompt, then the active history is rebuilt from the newest real
|
|
6
|
-
* user messages within one cumulative 20k-token budget plus one summary.
|
|
7
|
-
* Assistant messages, tool calls/results,
|
|
8
|
-
*
|
|
6
|
+
* user/system input messages within one cumulative 20k-token budget plus one summary.
|
|
7
|
+
* Assistant messages, tool calls/results, and reasoning are removed from the
|
|
8
|
+
* active model-facing history; retained input images and database audit rows remain.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import {
|
|
@@ -118,11 +118,16 @@ function itemRole(item: unknown): string | undefined {
|
|
|
118
118
|
return typeof role === "string" ? role : undefined;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/** A user-
|
|
121
|
+
/** A real user-role `message` item. */
|
|
122
122
|
export function isUserMessage(item: unknown): boolean {
|
|
123
123
|
return itemType(item) === "message" && itemRole(item) === "user";
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/** Accepted machine-input batches are canonical system messages, not user intent. */
|
|
127
|
+
function isPortableInputMessage(item: unknown): boolean {
|
|
128
|
+
return isUserMessage(item) || (itemType(item) === "message" && itemRole(item) === "system");
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
/** True for our synthetic compaction summary item. */
|
|
127
132
|
export function isCompactionSummary(item: unknown): boolean {
|
|
128
133
|
return (
|
|
@@ -1617,7 +1622,7 @@ function oldestLogicalUnitCuts(items: readonly CompactionItem[]): number[] {
|
|
|
1617
1622
|
|
|
1618
1623
|
/**
|
|
1619
1624
|
* Build the active history after compaction:
|
|
1620
|
-
* the newest
|
|
1625
|
+
* the newest user/system input messages that fit one cumulative, model-bounded budget
|
|
1621
1626
|
* (prior summaries excluded, retained images preserved) plus one marked summary item.
|
|
1622
1627
|
*/
|
|
1623
1628
|
export function buildCompactionReplacementHistory(
|
|
@@ -1633,7 +1638,7 @@ export function buildCompactionReplacementHistory(
|
|
|
1633
1638
|
);
|
|
1634
1639
|
for (let index = items.length - 1; index >= 0 && remaining > 0; index -= 1) {
|
|
1635
1640
|
const item = items[index]!;
|
|
1636
|
-
if (!
|
|
1641
|
+
if (!isPortableInputMessage(item) || isCompactionSummary(item) || isAttachmentCatalog(item)) {
|
|
1637
1642
|
continue;
|
|
1638
1643
|
}
|
|
1639
1644
|
const textTokens = estimateTextTokens(messageText(item));
|
|
@@ -1667,18 +1672,20 @@ export function isRemoteCompactionItem(item: unknown): item is CompactionItem {
|
|
|
1667
1672
|
);
|
|
1668
1673
|
}
|
|
1669
1674
|
|
|
1670
|
-
/** Messages retained beside a remote v2 compaction blob (user + developer). */
|
|
1675
|
+
/** Messages retained beside a remote v2 compaction blob (user + system + developer). */
|
|
1671
1676
|
export function isRetainedRemoteV2Message(item: unknown): boolean {
|
|
1672
1677
|
if (isCompactionSummary(item) || isAttachmentCatalog(item) || itemType(item) === "compaction") {
|
|
1673
1678
|
return false;
|
|
1674
1679
|
}
|
|
1675
1680
|
const role = itemRole(item);
|
|
1676
|
-
return
|
|
1681
|
+
return (
|
|
1682
|
+
itemType(item) === "message" && (role === "user" || role === "system" || role === "developer")
|
|
1683
|
+
);
|
|
1677
1684
|
}
|
|
1678
1685
|
|
|
1679
1686
|
/**
|
|
1680
1687
|
* Build the active history after Codex remote compaction v2:
|
|
1681
|
-
* newest retained user/developer messages within the CLI 64k budget plus the
|
|
1688
|
+
* newest retained user/system/developer messages within the CLI 64k budget plus the
|
|
1682
1689
|
* opaque `{ type: "compaction", encrypted_content }` item.
|
|
1683
1690
|
*
|
|
1684
1691
|
* Both modes preserve retained image parts. Charge their projected image
|
package/src/index.ts
CHANGED
|
@@ -6,11 +6,13 @@ import {
|
|
|
6
6
|
} from "./prepared-compaction-request";
|
|
7
7
|
export { preparedCompactionRequest, queuePreparedCompaction } from "./prepared-compaction-request";
|
|
8
8
|
import { AnthropicMessagesModel } from "./anthropic-messages";
|
|
9
|
+
export { AnthropicProviderRejection } from "./anthropic-messages";
|
|
9
10
|
import { instrumentedModelFetch } from "./model-provider-client";
|
|
10
11
|
import type { ModelProviderApi, ResolvedModelProvider, Settings } from "@opengeni/config";
|
|
11
12
|
import { isRunMcpCredentialError, RunMcpCredentials } from "./mcp-run-credentials";
|
|
12
13
|
import { normalizeCredentialProviderMcpUrl } from "@opengeni/contracts";
|
|
13
14
|
export { RunMcpCredentials, RunMcpCredentialError } from "./mcp-run-credentials";
|
|
15
|
+
export { AnthropicRequestError } from "./anthropic-request-error";
|
|
14
16
|
import { executeCommandReadWithRefresh } from "./command-read-refresh";
|
|
15
17
|
import {
|
|
16
18
|
captureMcpOperationDispatch,
|
|
@@ -266,6 +268,7 @@ import {
|
|
|
266
268
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
267
269
|
import { createHash, randomUUID } from "node:crypto";
|
|
268
270
|
import { dirname, isAbsolute, join, posix as posixPath } from "node:path";
|
|
271
|
+
import { gzipSync } from "node:zlib";
|
|
269
272
|
|
|
270
273
|
import { z } from "zod";
|
|
271
274
|
|
|
@@ -312,6 +315,7 @@ import {
|
|
|
312
315
|
createSandboxClient,
|
|
313
316
|
isModalTaskExecStartPreDispatchUnavailableError,
|
|
314
317
|
isModalCommandStartOutcomeUnknownError,
|
|
318
|
+
isProviderCommandObservationUnavailableError,
|
|
315
319
|
isRoutingMutationOutcomeUnknownError,
|
|
316
320
|
renderRoutingMutationOutcomeUnknownToolResult,
|
|
317
321
|
repairSerializedRunStateExposedPorts,
|
|
@@ -3974,6 +3978,9 @@ function buildAgentCapabilitiesFromComposition(
|
|
|
3974
3978
|
// Preserve that behavior except for client-side, pre-dispatch Modal
|
|
3975
3979
|
// readiness proof, which reaches bounded same-turn recovery.
|
|
3976
3980
|
execCommandErrorFunction: (_context, error) => {
|
|
3981
|
+
if (isProviderCommandObservationUnavailableError(error)) {
|
|
3982
|
+
return "Managed sandbox command observation unavailable. Outcome unknown. Do not replay the command or resend stdin; observe the existing invocation.";
|
|
3983
|
+
}
|
|
3977
3984
|
if (isModalTaskExecStartPreDispatchUnavailableError(error)) throw error;
|
|
3978
3985
|
if (isRoutingMutationOutcomeUnknownError(error)) {
|
|
3979
3986
|
// The outer physical fence must retain the exact process before
|
|
@@ -11766,11 +11773,11 @@ const RIG_SETUP_PROVIDER_IMAGE_MARKER_ROOT = "/var/opengeni";
|
|
|
11766
11773
|
// Modal's command transport caps aggregate argv at 64 KiB. Cancellation and
|
|
11767
11774
|
// run-as wrappers duplicate/expand this command, so stage moderate scripts too.
|
|
11768
11775
|
const RIG_SETUP_INLINE_COMMAND_MAX_BYTES = 4 * 1024;
|
|
11769
|
-
//
|
|
11770
|
-
//
|
|
11771
|
-
|
|
11772
|
-
const RIG_SETUP_PAYLOAD_CHUNK_CHARS = 7 * 1024;
|
|
11776
|
+
// Both cancellation and the SDK run-as wrapper repeat the payload three times.
|
|
11777
|
+
// Leave room for their fixed shell programs under Modal's 64-KiB argv ceiling.
|
|
11778
|
+
const RIG_SETUP_PAYLOAD_CHUNK_CHARS = 2 * 1024;
|
|
11773
11779
|
const RIG_SETUP_PAYLOAD_ROOT = "/tmp/opengeni/rig-setup-payloads";
|
|
11780
|
+
const RIG_SETUP_GZIP_SENTINEL = "__OPENGENI_SETUP_GZIP__";
|
|
11774
11781
|
|
|
11775
11782
|
export type RigSetupScriptCommandOptions = {
|
|
11776
11783
|
timeoutMs?: number;
|
|
@@ -11907,22 +11914,55 @@ async function stageRigSetupScript(
|
|
|
11907
11914
|
session: SandboxSessionLike,
|
|
11908
11915
|
script: string,
|
|
11909
11916
|
context: SandboxLifecycleHookContext,
|
|
11917
|
+
options: { payloadRoot?: string; label?: string } = {},
|
|
11910
11918
|
): Promise<string> {
|
|
11911
|
-
const
|
|
11919
|
+
const payloadRoot = options.payloadRoot ?? RIG_SETUP_PAYLOAD_ROOT;
|
|
11920
|
+
const payloadPath = `${payloadRoot}/${randomUUID()}.sh`;
|
|
11912
11921
|
const encodedPath = `${payloadPath}.b64`;
|
|
11913
|
-
const
|
|
11914
|
-
const
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11922
|
+
const bytes = Buffer.from(script, "utf8");
|
|
11923
|
+
const compressed = gzipSync(bytes);
|
|
11924
|
+
const compressionUseful = compressed.length < bytes.length;
|
|
11925
|
+
try {
|
|
11926
|
+
// Repeated shell programs compress well. Probe in the existing bootstrap
|
|
11927
|
+
// call, retaining the same bounded transfer on machines without gzip.
|
|
11928
|
+
const bootstrap = await runSandboxLifecycleCommand(
|
|
11929
|
+
session,
|
|
11930
|
+
{
|
|
11931
|
+
cmd: [
|
|
11932
|
+
"set -eu",
|
|
11933
|
+
"umask 077",
|
|
11934
|
+
`mkdir -p ${shellQuote(payloadRoot)}`,
|
|
11935
|
+
`: > ${shellQuote(encodedPath)}`,
|
|
11936
|
+
...(compressionUseful
|
|
11937
|
+
? [
|
|
11938
|
+
`if command -v gzip >/dev/null 2>&1; then printf '%s\\n' ${shellQuote(RIG_SETUP_GZIP_SENTINEL)}; fi`,
|
|
11939
|
+
]
|
|
11940
|
+
: []),
|
|
11941
|
+
].join("\n"),
|
|
11942
|
+
workdir: "/workspace",
|
|
11943
|
+
...(context.runAs ? { runAs: context.runAs } : {}),
|
|
11944
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
11945
|
+
maxOutputTokens: 4_000,
|
|
11946
|
+
},
|
|
11947
|
+
context.commandRunner,
|
|
11948
|
+
);
|
|
11949
|
+
assertSandboxCommandSucceeded(
|
|
11950
|
+
bootstrap,
|
|
11951
|
+
options.label ?? "Sandbox Environment setup payload staging",
|
|
11952
|
+
);
|
|
11953
|
+
const useCompression =
|
|
11954
|
+
compressionUseful &&
|
|
11955
|
+
sandboxCommandOutput(bootstrap).split(/\r?\n/u).includes(RIG_SETUP_GZIP_SENTINEL);
|
|
11956
|
+
const encoded = (useCompression ? compressed : bytes).toString("base64");
|
|
11957
|
+
const commands: string[] = [];
|
|
11958
|
+
for (let offset = 0; offset < encoded.length; offset += RIG_SETUP_PAYLOAD_CHUNK_CHARS) {
|
|
11959
|
+
commands.push(
|
|
11960
|
+
`printf '%s' ${shellQuote(encoded.slice(offset, offset + RIG_SETUP_PAYLOAD_CHUNK_CHARS))} >> ${shellQuote(encodedPath)}`,
|
|
11961
|
+
);
|
|
11962
|
+
}
|
|
11918
11963
|
commands.push(
|
|
11919
|
-
`
|
|
11964
|
+
`set -eu\nbase64 -d < ${shellQuote(encodedPath)}${useCompression ? " | gzip -dc" : ""} > ${shellQuote(payloadPath)}\nchmod 0700 ${shellQuote(payloadPath)}\nrm -f ${shellQuote(encodedPath)}`,
|
|
11920
11965
|
);
|
|
11921
|
-
}
|
|
11922
|
-
commands.push(
|
|
11923
|
-
`set -eu\nbase64 -d ${shellQuote(encodedPath)} > ${shellQuote(payloadPath)}\nchmod 0700 ${shellQuote(payloadPath)}\nrm -f ${shellQuote(encodedPath)}`,
|
|
11924
|
-
);
|
|
11925
|
-
try {
|
|
11926
11966
|
for (const command of commands) {
|
|
11927
11967
|
const result = await runSandboxLifecycleCommand(
|
|
11928
11968
|
session,
|
|
@@ -11935,7 +11975,10 @@ async function stageRigSetupScript(
|
|
|
11935
11975
|
},
|
|
11936
11976
|
context.commandRunner,
|
|
11937
11977
|
);
|
|
11938
|
-
assertSandboxCommandSucceeded(
|
|
11978
|
+
assertSandboxCommandSucceeded(
|
|
11979
|
+
result,
|
|
11980
|
+
options.label ?? "Sandbox Environment setup payload staging",
|
|
11981
|
+
);
|
|
11939
11982
|
}
|
|
11940
11983
|
return payloadPath;
|
|
11941
11984
|
} catch (error) {
|
|
@@ -12168,6 +12211,7 @@ export async function runRepositoryCloneHook(
|
|
|
12168
12211
|
editor: null,
|
|
12169
12212
|
staged: [],
|
|
12170
12213
|
};
|
|
12214
|
+
let stagedCloneScript: string | null = null;
|
|
12171
12215
|
try {
|
|
12172
12216
|
// Direct provider tokens retain the established off-manifest per-exec seed.
|
|
12173
12217
|
// Smart-Git broker bearers take a stricter path: stage opaque bytes through
|
|
@@ -12195,9 +12239,19 @@ export async function runRepositoryCloneHook(
|
|
|
12195
12239
|
stagedBrokerSeeds.staged,
|
|
12196
12240
|
options,
|
|
12197
12241
|
);
|
|
12198
|
-
|
|
12242
|
+
let command = sandboxGitProvisioningCommand(
|
|
12199
12243
|
seedPrefix ? `${seedPrefix}\n${cloneCommand}` : cloneCommand,
|
|
12200
12244
|
);
|
|
12245
|
+
// SDK setup also wraps run-as commands and cancellation can expand them.
|
|
12246
|
+
// Reuse the bounded script transport instead of sending the whole clone
|
|
12247
|
+
// program through those nested shell arguments.
|
|
12248
|
+
if (Buffer.byteLength(command, "utf8") > RIG_SETUP_INLINE_COMMAND_MAX_BYTES) {
|
|
12249
|
+
stagedCloneScript = await stageRigSetupScript(session, command, context, {
|
|
12250
|
+
payloadRoot: "/tmp/opengeni/repository-setup-payloads",
|
|
12251
|
+
label: "Repository setup payload staging",
|
|
12252
|
+
});
|
|
12253
|
+
command = `exec /bin/sh ${shellQuote(stagedCloneScript)}`;
|
|
12254
|
+
}
|
|
12201
12255
|
const result = await runSandboxLifecycleCommand(
|
|
12202
12256
|
session,
|
|
12203
12257
|
{
|
|
@@ -12237,6 +12291,19 @@ export async function runRepositoryCloneHook(
|
|
|
12237
12291
|
});
|
|
12238
12292
|
throw error;
|
|
12239
12293
|
} finally {
|
|
12294
|
+
if (stagedCloneScript) {
|
|
12295
|
+
await runSandboxLifecycleCommand(
|
|
12296
|
+
session,
|
|
12297
|
+
{
|
|
12298
|
+
cmd: `rm -f ${shellQuote(stagedCloneScript)} ${shellQuote(`${stagedCloneScript}.b64`)}`,
|
|
12299
|
+
workdir: "/workspace",
|
|
12300
|
+
...(context.runAs ? { runAs: context.runAs } : {}),
|
|
12301
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
12302
|
+
maxOutputTokens: 1_000,
|
|
12303
|
+
},
|
|
12304
|
+
context.commandRunner,
|
|
12305
|
+
).catch(() => undefined);
|
|
12306
|
+
}
|
|
12240
12307
|
if (stagedBrokerSeeds.editor) {
|
|
12241
12308
|
await cleanupStagedGitCredentialSeeds(stagedBrokerSeeds.editor, stagedBrokerSeeds.staged);
|
|
12242
12309
|
}
|
package/src/interaction-tools.ts
CHANGED
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
BrowserActionReceipt,
|
|
10
10
|
BrowserClipboard,
|
|
11
11
|
BrowserDiagnosticBatch,
|
|
12
|
+
BrowserDownload,
|
|
13
|
+
BrowserDownloadListResponse,
|
|
14
|
+
BrowserDownloadSaveRequest,
|
|
15
|
+
BrowserDownloadSaveResponse,
|
|
12
16
|
BrowserDomReadResponse,
|
|
13
17
|
BrowserDomReadLocator,
|
|
14
18
|
BrowserDomReadSelector,
|
|
@@ -279,6 +283,8 @@ const TOOL_PERMISSION = {
|
|
|
279
283
|
browser_act: "sessions:control",
|
|
280
284
|
browser_clipboard: "sessions:read",
|
|
281
285
|
browser_debug: "sessions:read",
|
|
286
|
+
browser_downloads: "sessions:read",
|
|
287
|
+
browser_download_save: ["sessions:control", "files:upload"],
|
|
282
288
|
browser_auth: "sessions:control",
|
|
283
289
|
interaction_request_human: "sessions:control",
|
|
284
290
|
browser_identity: "sessions:control",
|
|
@@ -290,7 +296,7 @@ const TOOL_PERMISSION = {
|
|
|
290
296
|
computer_clipboard: "sessions:read",
|
|
291
297
|
computer_act: "sessions:control",
|
|
292
298
|
computer_lifecycle: "sessions:control",
|
|
293
|
-
} as const satisfies Record<InteractionAttemptToolName, Permission>;
|
|
299
|
+
} as const satisfies Record<InteractionAttemptToolName, Permission | readonly Permission[]>;
|
|
294
300
|
|
|
295
301
|
const DiscoveryInput = z
|
|
296
302
|
.object({
|
|
@@ -618,6 +624,26 @@ const ComputerLifecycleInput = z
|
|
|
618
624
|
|
|
619
625
|
const TERMINAL_LIFECYCLES = new Set(["ended", "failed"]);
|
|
620
626
|
|
|
627
|
+
const BrowserDownloadsInput = z
|
|
628
|
+
.object({
|
|
629
|
+
browserSessionId: z.string().uuid(),
|
|
630
|
+
operation: z.enum(["list", "get"]).default("list"),
|
|
631
|
+
downloadId: z.string().uuid().optional(),
|
|
632
|
+
})
|
|
633
|
+
.strict()
|
|
634
|
+
.superRefine((value, context) => {
|
|
635
|
+
if ((value.operation === "get") !== (value.downloadId !== undefined)) {
|
|
636
|
+
context.addIssue({
|
|
637
|
+
code: "custom",
|
|
638
|
+
path: ["downloadId"],
|
|
639
|
+
message: "downloadId is required only for operation=get",
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
const BrowserDownloadSaveInput = BrowserDownloadSaveRequest.omit({ operationId: true })
|
|
644
|
+
.extend({ browserSessionId: z.string().uuid(), downloadId: z.string().uuid() })
|
|
645
|
+
.strict();
|
|
646
|
+
|
|
621
647
|
export type CreateInteractionAttemptToolsInput = {
|
|
622
648
|
transport: InteractionTransport;
|
|
623
649
|
workspaceId: string;
|
|
@@ -1039,6 +1065,82 @@ export function createInteractionAttemptToolDefinitions(
|
|
|
1039
1065
|
),
|
|
1040
1066
|
});
|
|
1041
1067
|
|
|
1068
|
+
add({
|
|
1069
|
+
name: "browser_downloads",
|
|
1070
|
+
codemodePath: ["interaction", "browser", "downloads"],
|
|
1071
|
+
title: "Inspect browser downloads",
|
|
1072
|
+
description:
|
|
1073
|
+
"List browser-produced files or get one exact download by id. Metadata identifies completed bytes and their SHA-256; diagnostics alone do not expose a download id or file bytes. Use browser_download_save to materialize a completed download in its source session's workspace. Attached browsers and Lightpanda do not expose managed downloads.",
|
|
1074
|
+
input: BrowserDownloadsInput,
|
|
1075
|
+
output: z.union([BrowserDownloadListResponse, BrowserDownload]),
|
|
1076
|
+
readOnly: true,
|
|
1077
|
+
idempotent: true,
|
|
1078
|
+
execute: async (value) => {
|
|
1079
|
+
if (value.operation === "get") {
|
|
1080
|
+
const download = await input.transport.getBrowserDownload(
|
|
1081
|
+
input.workspaceId,
|
|
1082
|
+
value.browserSessionId,
|
|
1083
|
+
value.downloadId!,
|
|
1084
|
+
);
|
|
1085
|
+
if (
|
|
1086
|
+
download.browserSessionId !== value.browserSessionId ||
|
|
1087
|
+
download.id !== value.downloadId
|
|
1088
|
+
) {
|
|
1089
|
+
throw new Error("Browser download belongs to another resource");
|
|
1090
|
+
}
|
|
1091
|
+
return download;
|
|
1092
|
+
}
|
|
1093
|
+
const response = await input.transport.listBrowserDownloads(
|
|
1094
|
+
input.workspaceId,
|
|
1095
|
+
value.browserSessionId,
|
|
1096
|
+
);
|
|
1097
|
+
if (
|
|
1098
|
+
response.browserSessionId !== value.browserSessionId ||
|
|
1099
|
+
response.downloads.some(
|
|
1100
|
+
(download) =>
|
|
1101
|
+
download.browserSessionId !== value.browserSessionId ||
|
|
1102
|
+
download.controllerGeneration !== response.controllerGeneration,
|
|
1103
|
+
)
|
|
1104
|
+
) {
|
|
1105
|
+
throw new Error("Browser downloads belong to another session binding");
|
|
1106
|
+
}
|
|
1107
|
+
return response;
|
|
1108
|
+
},
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
add({
|
|
1112
|
+
name: "browser_download_save",
|
|
1113
|
+
codemodePath: ["interaction", "browser", "downloadSave"],
|
|
1114
|
+
title: "Save browser download to workspace",
|
|
1115
|
+
description:
|
|
1116
|
+
"Save one exact completed managed browser download to a portable relative path in the browser's source session workspace. Requires sessions:control and files:upload. Returns the materialized destinationPath, fileId and integrity metadata; read the saved bytes with ordinary workspace file tools. Existing files are protected unless overwrite=true. The attempt operation id fences retries; uncertain outcomes must reconcile that same operation. Attached browsers and Lightpanda cannot publish managed downloads.",
|
|
1117
|
+
input: BrowserDownloadSaveInput,
|
|
1118
|
+
output: BrowserDownloadSaveResponse,
|
|
1119
|
+
readOnly: false,
|
|
1120
|
+
idempotent: true,
|
|
1121
|
+
execute: async (value, context) => {
|
|
1122
|
+
const response = await input.transport.saveBrowserDownload(
|
|
1123
|
+
input.workspaceId,
|
|
1124
|
+
value.browserSessionId,
|
|
1125
|
+
value.downloadId,
|
|
1126
|
+
{
|
|
1127
|
+
operationId: context.operationId,
|
|
1128
|
+
destinationPath: value.destinationPath,
|
|
1129
|
+
overwrite: value.overwrite,
|
|
1130
|
+
},
|
|
1131
|
+
);
|
|
1132
|
+
if (
|
|
1133
|
+
response.download.browserSessionId !== value.browserSessionId ||
|
|
1134
|
+
response.download.id !== value.downloadId ||
|
|
1135
|
+
response.operationId !== context.operationId ||
|
|
1136
|
+
response.destinationPath !== value.destinationPath
|
|
1137
|
+
) {
|
|
1138
|
+
throw new Error("Browser download save returned another operation binding");
|
|
1139
|
+
}
|
|
1140
|
+
return response;
|
|
1141
|
+
},
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1042
1144
|
add({
|
|
1043
1145
|
name: "browser_auth",
|
|
1044
1146
|
codemodePath: ["interaction", "browser", "auth"],
|
|
@@ -1992,8 +2094,16 @@ function jsonSchema(schema: z.ZodType): AttemptToolJsonSchema {
|
|
|
1992
2094
|
return z.toJSONSchema(schema, { target: "draft-2020-12" }) as AttemptToolJsonSchema;
|
|
1993
2095
|
}
|
|
1994
2096
|
|
|
1995
|
-
function hasToolPermission(
|
|
1996
|
-
|
|
2097
|
+
function hasToolPermission(
|
|
2098
|
+
permissions: readonly Permission[],
|
|
2099
|
+
required: Permission | readonly Permission[],
|
|
2100
|
+
): boolean {
|
|
2101
|
+
return (
|
|
2102
|
+
permissions.includes("workspace:admin") ||
|
|
2103
|
+
(typeof required === "string" ? [required] : required).every((permission) =>
|
|
2104
|
+
permissions.includes(permission),
|
|
2105
|
+
)
|
|
2106
|
+
);
|
|
1997
2107
|
}
|
|
1998
2108
|
|
|
1999
2109
|
function firstPartyApiBaseUrl(settings: Settings, workspaceId: string): string {
|
|
@@ -477,10 +477,10 @@ export class LazyToolRuntime {
|
|
|
477
477
|
typeof args.limit === "number" && Number.isFinite(args.limit)
|
|
478
478
|
? Math.max(1, Math.min(40, Math.floor(args.limit)))
|
|
479
479
|
: 20;
|
|
480
|
-
const
|
|
480
|
+
const authorizedTools = [...new Set(this.searchableTools(this.currentTools))]
|
|
481
481
|
.filter(isFunctionTool)
|
|
482
|
-
.filter((tool) => tool.name.startsWith(prefix))
|
|
483
482
|
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
483
|
+
const tools = authorizedTools.filter((tool) => tool.name.startsWith(prefix));
|
|
484
484
|
const cursorIndex =
|
|
485
485
|
cursor === undefined ? -1 : tools.findIndex((tool) => tool.name === cursor);
|
|
486
486
|
if (cursor !== undefined && cursorIndex === -1) {
|
|
@@ -513,17 +513,33 @@ export class LazyToolRuntime {
|
|
|
513
513
|
}
|
|
514
514
|
descriptors.push(descriptor);
|
|
515
515
|
}
|
|
516
|
-
|
|
516
|
+
const result = {
|
|
517
517
|
tools: descriptors,
|
|
518
518
|
total: tools.length,
|
|
519
519
|
nextCursor: index < tools.length ? descriptors.at(-1)!.name : null,
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
520
|
+
};
|
|
521
|
+
if (!prefix || tools.length > 0) return JSON.stringify(result);
|
|
522
|
+
|
|
523
|
+
// Preserve literal-prefix pagination. Recovery hints are descriptors
|
|
524
|
+
// from the same authorized deferred pool, never schemas or new grants.
|
|
525
|
+
const recovery = {
|
|
526
|
+
...result,
|
|
527
|
+
message:
|
|
528
|
+
"No tool names match this literal prefix. This does not establish capability absence. Load any suggested exact names with tool_search, or retry tool_list without namePrefix to browse the authorized catalog.",
|
|
529
|
+
suggestions: [] as { name: string; description: string }[],
|
|
530
|
+
};
|
|
531
|
+
for (const candidate of authorizedTools) {
|
|
532
|
+
if (!candidate.name.includes(prefix)) continue;
|
|
533
|
+
const suggestion = {
|
|
534
|
+
name: candidate.name,
|
|
535
|
+
description: Array.from(candidate.description).slice(0, 160).join(""),
|
|
536
|
+
};
|
|
537
|
+
const next = { ...recovery, suggestions: [...recovery.suggestions, suggestion] };
|
|
538
|
+
if (Buffer.byteLength(JSON.stringify(next)) > 16 * 1024) continue;
|
|
539
|
+
recovery.suggestions.push(suggestion);
|
|
540
|
+
if (recovery.suggestions.length >= Math.min(limit, 8)) break;
|
|
541
|
+
}
|
|
542
|
+
return JSON.stringify(recovery);
|
|
527
543
|
},
|
|
528
544
|
}) as unknown as Tool;
|
|
529
545
|
}
|
package/src/mcp-network.ts
CHANGED
|
@@ -17,7 +17,9 @@ export const MCP_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
|
17
17
|
// a lower HTTP limit rejects valid calls before the tool can execute and turns
|
|
18
18
|
// a deterministic transport refusal into apparent outcome uncertainty.
|
|
19
19
|
export const MCP_MAX_INBOUND_REQUEST_BYTES = CODEMODE_ARGUMENTS_MAX_BYTES + 64 * 1024;
|
|
20
|
-
|
|
20
|
+
// Rich nested schemas fit within one bounded discovery/disclosure envelope.
|
|
21
|
+
// Whole-server and aggregate limits still bound the complete catalog.
|
|
22
|
+
export const MCP_MAX_TOOL_DEFINITION_BYTES = 512 * 1024;
|
|
21
23
|
export const MCP_MAX_TOOL_LIST_BYTES = 4 * 1024 * 1024;
|
|
22
24
|
export const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = MCP_MAX_CATALOG_TOOL_ENTRIES;
|
|
23
25
|
// One provider may use the available catalog allowance. The shared budget
|
|
@@ -25,7 +27,7 @@ export const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = MCP_MAX_CATALOG_TOOL_ENTRIES;
|
|
|
25
27
|
// silently excluded otherwise bounded catalogs from best-effort discovery.
|
|
26
28
|
export const MCP_MAX_TOOL_LIST_ENTRIES = MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES;
|
|
27
29
|
export const MCP_MAX_TOOL_RESULT_BYTES = 1024 * 1024;
|
|
28
|
-
export const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES =
|
|
30
|
+
export const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES = MCP_MAX_TOOL_DEFINITION_BYTES + 16 * 1024;
|
|
29
31
|
export const MCP_MAX_SELECTED_SERVERS = 64;
|
|
30
32
|
export const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
|
|
31
33
|
// @openai/agents has a separate lifecycle fence around MCPServer.connect().
|
|
@@ -30,7 +30,7 @@ import { recordModelTransportStarted } from "./model-preparation-diagnostics";
|
|
|
30
30
|
import { captureProviderRequestBody } from "./model-request-capture";
|
|
31
31
|
import { withoutQuotaExhaustedRetries } from "./provider-quota";
|
|
32
32
|
import {
|
|
33
|
-
|
|
33
|
+
captureClaudeRequestToken,
|
|
34
34
|
prepareClaudeSubscriptionRequest,
|
|
35
35
|
} from "./claude-subscription-usage";
|
|
36
36
|
|
|
@@ -266,6 +266,12 @@ function withoutAuthenticationHeaders(inner: typeof fetch): typeof fetch {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
export function buildProviderClient(provider: ResolvedModelProvider, settings: Settings): OpenAI {
|
|
269
|
+
if (
|
|
270
|
+
(provider.kind === "direct-openai-workspace" || provider.kind === "direct-azure-workspace") &&
|
|
271
|
+
!provider.apiKey?.trim()
|
|
272
|
+
) {
|
|
273
|
+
throw new Error("OpenAI or Azure OpenAI workspace key is unavailable");
|
|
274
|
+
}
|
|
269
275
|
const workspaceGateway = provider.kind === "vercel-gateway-workspace";
|
|
270
276
|
const scopedCredentialProvider =
|
|
271
277
|
provider.credentialSource?.kind === "workspace_connection" ||
|
|
@@ -403,7 +409,9 @@ export function instrumentedModelFetch(provider: string, inner: typeof fetch): t
|
|
|
403
409
|
if (!isModelCallFetch(input)) {
|
|
404
410
|
return await inner(input, init);
|
|
405
411
|
}
|
|
406
|
-
|
|
412
|
+
const prepared = await prepareClaudeSubscriptionRequest(provider, input, init);
|
|
413
|
+
init = prepared.init;
|
|
414
|
+
const claudeRequestToken = captureClaudeRequestToken(input, init);
|
|
407
415
|
// The attempt-local observer durably checkpoints provider dispatch before
|
|
408
416
|
// this process can place request bytes on the network.
|
|
409
417
|
await recordModelTransportStarted();
|
|
@@ -411,7 +419,7 @@ export function instrumentedModelFetch(provider: string, inner: typeof fetch): t
|
|
|
411
419
|
const started = performance.now();
|
|
412
420
|
try {
|
|
413
421
|
const response = await inner(input, capture.init);
|
|
414
|
-
|
|
422
|
+
prepared.observe(response, claudeRequestToken);
|
|
415
423
|
recordModelCallMetric(provider, response.ok ? "completed" : "failed", started);
|
|
416
424
|
return response;
|
|
417
425
|
} catch (error) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDirectModelId } from "@opengeni/contracts";
|
|
1
2
|
import type { ConfiguredModel, ResolvedModelProvider, Settings } from "@opengeni/config";
|
|
2
3
|
import { configuredProviders, resolveModelProvider } from "@opengeni/config";
|
|
3
4
|
import {
|
|
@@ -334,6 +335,9 @@ export class MultiProviderModelProvider implements ModelProvider {
|
|
|
334
335
|
throw new XaiSubscriptionUnavailableError(modelName);
|
|
335
336
|
}
|
|
336
337
|
}
|
|
338
|
+
if (modelName && isDirectModelId(modelName)) {
|
|
339
|
+
throw new Error("The selected OpenAI or Azure OpenAI connection is unavailable");
|
|
340
|
+
}
|
|
337
341
|
// Preserve the legacy unlisted-model fallback, but bind it through the same
|
|
338
342
|
// typed request-policy model as every configured Responses call. This keeps
|
|
339
343
|
// Azure wire normalization at the object stage instead of reintroducing a
|
package/src/runtime-skills.ts
CHANGED
|
@@ -50,6 +50,7 @@ export type NativeToolSkillSet = Readonly<{
|
|
|
50
50
|
defaults?: boolean;
|
|
51
51
|
editableArtifacts: boolean;
|
|
52
52
|
sites?: boolean;
|
|
53
|
+
schedules?: boolean;
|
|
53
54
|
videoGeneration: boolean;
|
|
54
55
|
}>;
|
|
55
56
|
|
|
@@ -121,6 +122,7 @@ export function loadNativeToolSkillArtifacts(
|
|
|
121
122
|
): readonly RuntimeSkillArtifact[] {
|
|
122
123
|
const directories: string[] = nativeTools.defaults === false ? [] : ["bundled_default_skills"];
|
|
123
124
|
if (nativeTools.projects) directories.push("bundled_project_skills");
|
|
125
|
+
if (nativeTools.schedules) directories.push("bundled_schedule_skills");
|
|
124
126
|
if (nativeTools.editableArtifacts) directories.push("bundled_artifact_skills");
|
|
125
127
|
if (nativeTools.sites) directories.push("bundled_site_skills");
|
|
126
128
|
if (nativeTools.videoGeneration) directories.push("bundled_video_skills");
|
|
@@ -391,6 +393,12 @@ function nativeToolSkillSources(nativeTools: NativeToolSkillSet): Array<{
|
|
|
391
393
|
reason: "bundled Site authoring skill",
|
|
392
394
|
});
|
|
393
395
|
}
|
|
396
|
+
if (nativeTools.schedules) {
|
|
397
|
+
sources.push({
|
|
398
|
+
names: skillDirNames(packagedSkillDirectory("bundled_schedule_skills")),
|
|
399
|
+
reason: "native scheduled-task tool surface",
|
|
400
|
+
});
|
|
401
|
+
}
|
|
394
402
|
if (nativeTools.videoGeneration) {
|
|
395
403
|
sources.push({
|
|
396
404
|
names: skillDirNames(packagedSkillDirectory("bundled_video_skills")),
|
package/src/sandbox/channel-a.ts
CHANGED
|
@@ -178,6 +178,7 @@ export type ChannelASession = ProviderCommandSession & {
|
|
|
178
178
|
chars?: string;
|
|
179
179
|
yieldTimeMs?: number;
|
|
180
180
|
maxOutputTokens?: number;
|
|
181
|
+
signal?: AbortSignal;
|
|
181
182
|
}): Promise<string>;
|
|
182
183
|
writeStdinForProcessMutation?(args: {
|
|
183
184
|
sessionId: number;
|
|
@@ -193,6 +194,8 @@ export type ChannelASession = ProviderCommandSession & {
|
|
|
193
194
|
}): Promise<string>;
|
|
194
195
|
cancelExecCommand?(opId: string): Promise<boolean>;
|
|
195
196
|
hasRetainedProcess?(providerSessionId: number): boolean;
|
|
197
|
+
/** Cleanup only: forget the local route after exact durable terminal proof. */
|
|
198
|
+
reconcileRetainedProcess?(providerSessionId: number): Promise<boolean>;
|
|
196
199
|
retainedProcessHasTypedHandleLoss?(providerSessionId: number): boolean;
|
|
197
200
|
execCommandForProcessControl?(providerSessionId: number, args: ChannelAExecArgs): Promise<string>;
|
|
198
201
|
createEditor?(runAs?: string): ChannelAEditor;
|
package/src/sandbox/index.ts
CHANGED
|
@@ -2,7 +2,11 @@ export type {
|
|
|
2
2
|
ProviderCommandPersistence,
|
|
3
3
|
ProviderCommandSession,
|
|
4
4
|
} from "./provider-command-session";
|
|
5
|
-
export {
|
|
5
|
+
export {
|
|
6
|
+
ProviderCommandStartOutcomeUnknownError,
|
|
7
|
+
ProviderCommandObservationUnavailableError,
|
|
8
|
+
isProviderCommandObservationUnavailableError,
|
|
9
|
+
} from "./provider-command-session";
|
|
6
10
|
// @opengeni/runtime/sandbox — the agent-loop-free sandbox leaf.
|
|
7
11
|
//
|
|
8
12
|
// This module is the load-bearing pre-req for the API-direct control plane
|
|
@@ -26,6 +30,12 @@ export { ProviderCommandStartOutcomeUnknownError } from "./provider-command-sess
|
|
|
26
30
|
import type { Settings } from "@opengeni/config";
|
|
27
31
|
import { collectSandboxEnvironment, parseExposedPorts } from "@opengeni/config";
|
|
28
32
|
export type { WorkspaceArchiveSpool, VerifiedHostWorkspaceArchive } from "./archive-spool";
|
|
33
|
+
export { reduceModalRawOutputPage } from "./providers/modal-command-raw-page";
|
|
34
|
+
export type {
|
|
35
|
+
ModalRawOutputPage,
|
|
36
|
+
ModalRawOutputStreams,
|
|
37
|
+
ModalRawOutputExit,
|
|
38
|
+
} from "./providers/modal-command-raw-page";
|
|
29
39
|
import type { WorkspaceArchiveSpool } from "./archive-spool";
|
|
30
40
|
import { restoreHostWorkspaceArchive } from "./host-archive-spool";
|
|
31
41
|
export {
|