@opengeni/runtime 2.4.3 → 2.5.2-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-UA75SUZ7.js → agent-Q2VNH5FV.js} +2 -2
- package/dist/{chunk-ORKCCH5X.js → chunk-25B3EQRW.js} +3 -398
- package/dist/{chunk-ORKCCH5X.js.map → chunk-25B3EQRW.js.map} +1 -1
- package/dist/{chunk-YRKIQK25.js → chunk-CD22I76N.js} +2 -2
- package/dist/{chunk-7K6WOXFS.js → chunk-GB763TSV.js} +17 -1
- package/dist/chunk-GB763TSV.js.map +1 -0
- package/dist/{chunk-BV2DSPZK.js → chunk-GBHOT4KS.js} +267 -181
- package/dist/chunk-GBHOT4KS.js.map +1 -0
- package/dist/{chunk-WATBACLT.js → chunk-LEIGL6X2.js} +2309 -1428
- package/dist/chunk-LEIGL6X2.js.map +1 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.js +15 -5
- package/dist/{localSources-GDQRRHT3.js → localSources-Z5IJIIRV.js} +3 -3
- package/dist/model-input.d.ts +2 -1
- package/dist/runtime-skills.d.ts +28 -5
- package/dist/sandbox/archive-spool.d.ts +14 -0
- package/dist/sandbox/host-archive-spool.d.ts +19 -0
- package/dist/sandbox/index.d.ts +5 -1
- package/dist/sandbox/index.js +7 -3
- package/dist/sandbox/workspace-archive.d.ts +7 -0
- package/dist/skill-files.d.ts +4 -0
- package/dist/skill-library.d.ts +1 -1
- package/dist/skill-library.js +3 -1
- package/dist/workspace-tool-gateway.js +5 -5
- package/package.json +11 -11
- package/src/bundled_management_skills/opengeni-skills/SKILL.md +3 -1
- package/src/index.ts +184 -33
- package/src/lazy-tool-transport.ts +0 -3
- package/src/model-input.ts +1 -1
- package/src/run-events.ts +23 -0
- package/src/runtime-skills.ts +122 -161
- package/src/sandbox/archive-spool.ts +16 -0
- package/src/sandbox/host-archive-spool.ts +1040 -0
- package/src/sandbox/index.ts +292 -203
- package/src/sandbox/routing/routing-session.ts +1 -1
- package/src/sandbox/workspace-archive.ts +54 -1
- package/src/skill-files.ts +20 -0
- package/src/skill-library.ts +1 -0
- package/dist/chunk-7K6WOXFS.js.map +0 -1
- package/dist/chunk-BV2DSPZK.js.map +0 -1
- package/dist/chunk-WATBACLT.js.map +0 -1
- /package/dist/{agent-UA75SUZ7.js.map → agent-Q2VNH5FV.js.map} +0 -0
- /package/dist/{chunk-YRKIQK25.js.map → chunk-CD22I76N.js.map} +0 -0
- /package/dist/{localSources-GDQRRHT3.js.map → localSources-Z5IJIIRV.js.map} +0 -0
package/src/index.ts
CHANGED
|
@@ -184,6 +184,7 @@ import {
|
|
|
184
184
|
type SerializedTool,
|
|
185
185
|
type Tool,
|
|
186
186
|
} from "@openai/agents";
|
|
187
|
+
import { getToolSearchExecution, getToolSearchProviderCallId } from "@openai/agents-core/utils";
|
|
187
188
|
import {
|
|
188
189
|
Capabilities,
|
|
189
190
|
Manifest,
|
|
@@ -196,7 +197,6 @@ import {
|
|
|
196
197
|
inContainerMountStrategy,
|
|
197
198
|
s3Mount,
|
|
198
199
|
shell,
|
|
199
|
-
skills,
|
|
200
200
|
type SandboxClient,
|
|
201
201
|
type SandboxSessionLike,
|
|
202
202
|
type SandboxSessionState,
|
|
@@ -214,6 +214,8 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
214
214
|
import { createHash, randomUUID } from "node:crypto";
|
|
215
215
|
import { dirname, isAbsolute, join, posix as posixPath } from "node:path";
|
|
216
216
|
|
|
217
|
+
import { z } from "zod";
|
|
218
|
+
|
|
217
219
|
import { sanitizeHistoryItemsForModel } from "./history-sanitizer";
|
|
218
220
|
import { OPENGENI_OPERATIONAL_INSTRUCTIONS } from "./operational-instructions";
|
|
219
221
|
import {
|
|
@@ -277,13 +279,18 @@ import {
|
|
|
277
279
|
import { workspaceSkills, type WorkspaceSkillSearchPath } from "./workspace-skills";
|
|
278
280
|
import {
|
|
279
281
|
composeRuntimeSkills,
|
|
282
|
+
readRuntimeSkill,
|
|
283
|
+
skillCatalogFromComposition,
|
|
280
284
|
type EffectiveSkillSelection,
|
|
281
285
|
type RuntimeSkillActivation,
|
|
282
286
|
type RuntimeSkillComposition,
|
|
287
|
+
type RuntimeSkillIndexEntry,
|
|
283
288
|
} from "./runtime-skills";
|
|
284
289
|
export {
|
|
285
290
|
composeRuntimeSkills,
|
|
286
291
|
loadNativeToolSkillArtifacts,
|
|
292
|
+
readRuntimeSkill,
|
|
293
|
+
skillCatalogFromComposition,
|
|
287
294
|
type EffectiveSkillSelection,
|
|
288
295
|
type InstalledSkillActivation,
|
|
289
296
|
type NativeToolSkillSet,
|
|
@@ -293,6 +300,7 @@ export {
|
|
|
293
300
|
type RuntimeSkillArtifactFile,
|
|
294
301
|
type RuntimeSkillComposition,
|
|
295
302
|
type RuntimeSkillDescriptor,
|
|
303
|
+
type RuntimeSkillIndexEntry,
|
|
296
304
|
type SessionSkillActivation,
|
|
297
305
|
} from "./runtime-skills";
|
|
298
306
|
import {
|
|
@@ -316,6 +324,7 @@ import {
|
|
|
316
324
|
composeCallModelInputFilters,
|
|
317
325
|
contextRobustnessFilterForSettings,
|
|
318
326
|
incrementalModelInputProjectionFilter,
|
|
327
|
+
stripProviderItemId,
|
|
319
328
|
} from "./model-input";
|
|
320
329
|
import {
|
|
321
330
|
recordModelPreparationManifestInventory,
|
|
@@ -1014,9 +1023,12 @@ export async function summarizeForCompaction(
|
|
|
1014
1023
|
// items without flattening tool history into a fake user transcript.
|
|
1015
1024
|
const request: ModelRequest = {
|
|
1016
1025
|
systemInstructions: options.systemInstructions ?? "",
|
|
1017
|
-
input: input as AgentInputItem[],
|
|
1026
|
+
input: input.map(detachCompactionResponseItemIdentity) as AgentInputItem[],
|
|
1018
1027
|
modelSettings: {
|
|
1019
1028
|
maxTokens,
|
|
1029
|
+
// Azure can select a historical tool despite empty schemas. Keep this
|
|
1030
|
+
// verified policy off subscription/gateway transports with other contracts.
|
|
1031
|
+
...(provider.wireProfile === "azure-openai" ? { toolChoice: "none" as const } : {}),
|
|
1020
1032
|
// Azure rejects store:false; the Codex subscription transport enforces
|
|
1021
1033
|
// it independently. The OpenAI platform path remains explicitly storeless.
|
|
1022
1034
|
...(settings.openaiProvider === "azure" ? {} : { store: false }),
|
|
@@ -1050,6 +1062,47 @@ export async function summarizeForCompaction(
|
|
|
1050
1062
|
return summary;
|
|
1051
1063
|
}
|
|
1052
1064
|
|
|
1065
|
+
/**
|
|
1066
|
+
* Portable checkpoints carry inline history, not references to stored Responses
|
|
1067
|
+
* items. An assistant/tool item's provider id can require its original reasoning
|
|
1068
|
+
* item even when the full message is supplied. The portable preparation removes
|
|
1069
|
+
* opaque reasoning, so retaining those dependent ids makes Azure reject the
|
|
1070
|
+
* checkpoint. Remove only provider item identity from this request-local copy;
|
|
1071
|
+
* callId/call_id, tool payloads, order, and canonical history stay unchanged.
|
|
1072
|
+
*/
|
|
1073
|
+
const DETACHABLE_COMPACTION_ITEM_TYPES = new Set([
|
|
1074
|
+
"message",
|
|
1075
|
+
"reasoning",
|
|
1076
|
+
"function_call",
|
|
1077
|
+
"function_call_result",
|
|
1078
|
+
"shell_call",
|
|
1079
|
+
"shell_call_output",
|
|
1080
|
+
"computer_call",
|
|
1081
|
+
"computer_call_result",
|
|
1082
|
+
"apply_patch_call",
|
|
1083
|
+
"apply_patch_call_output",
|
|
1084
|
+
]);
|
|
1085
|
+
|
|
1086
|
+
function detachCompactionResponseItemIdentity(
|
|
1087
|
+
item: Record<string, unknown>,
|
|
1088
|
+
): Record<string, unknown> {
|
|
1089
|
+
const clientToolSearch =
|
|
1090
|
+
(item.type === "tool_search_call" || item.type === "tool_search_output") &&
|
|
1091
|
+
getToolSearchExecution(item) !== "server" &&
|
|
1092
|
+
Boolean(getToolSearchProviderCallId(item));
|
|
1093
|
+
const providerData = item.providerData as Record<string, unknown> | undefined;
|
|
1094
|
+
const webSearch =
|
|
1095
|
+
item.type === "hosted_tool_call" &&
|
|
1096
|
+
(providerData?.type === "web_search_call" || providerData?.type === "web_search");
|
|
1097
|
+
// Unlike web search, hosted file search requires its id on Azure input.
|
|
1098
|
+
// Approval/program references also remain intact. A universal strip is unsafe.
|
|
1099
|
+
if (!DETACHABLE_COMPACTION_ITEM_TYPES.has(String(item.type)) && !clientToolSearch && !webSearch)
|
|
1100
|
+
return item;
|
|
1101
|
+
// The SDK reserves providerData.id for these types; only the top-level id is
|
|
1102
|
+
// emitted. Share the normal inference primitive without changing its policy.
|
|
1103
|
+
return stripProviderItemId(item as AgentInputItem) as Record<string, unknown>;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1053
1106
|
/**
|
|
1054
1107
|
* Serialize the agent's model-visible tools for a remote_v2 compact request.
|
|
1055
1108
|
*
|
|
@@ -1287,11 +1340,13 @@ export function compactionProviderFailureDiagnostics(error: unknown): Record<str
|
|
|
1287
1340
|
let type: string | null = null;
|
|
1288
1341
|
let requestId: string | null = null;
|
|
1289
1342
|
let eventType: string | null = null;
|
|
1343
|
+
let rejectionReason: "missing_required_reasoning_item" | null = null;
|
|
1290
1344
|
const seen = new Set<object>();
|
|
1291
1345
|
for (let depth = 0; depth < 6 && current && typeof current === "object"; depth += 1) {
|
|
1292
1346
|
if (seen.has(current)) break;
|
|
1293
1347
|
seen.add(current);
|
|
1294
1348
|
const record = current as Record<string, unknown>;
|
|
1349
|
+
rejectionReason ??= compactionRejectionReason(record);
|
|
1295
1350
|
if (!errorName && current instanceof Error) {
|
|
1296
1351
|
errorName = boundCompactionDiagnosticField(current.name);
|
|
1297
1352
|
}
|
|
@@ -1342,6 +1397,7 @@ export function compactionProviderFailureDiagnostics(error: unknown): Record<str
|
|
|
1342
1397
|
const nestedError = record.error;
|
|
1343
1398
|
if (nestedError && typeof nestedError === "object" && !seen.has(nestedError)) {
|
|
1344
1399
|
const nested = nestedError as Record<string, unknown>;
|
|
1400
|
+
rejectionReason ??= compactionRejectionReason(nested);
|
|
1345
1401
|
if (code === null && typeof nested.code === "string") {
|
|
1346
1402
|
code = boundCompactionDiagnosticField(nested.code);
|
|
1347
1403
|
}
|
|
@@ -1372,9 +1428,24 @@ export function compactionProviderFailureDiagnostics(error: unknown): Record<str
|
|
|
1372
1428
|
type,
|
|
1373
1429
|
requestId,
|
|
1374
1430
|
...(eventType ? { eventType } : {}),
|
|
1431
|
+
...(rejectionReason ? { rejectionReason } : {}),
|
|
1375
1432
|
};
|
|
1376
1433
|
}
|
|
1377
1434
|
|
|
1435
|
+
function compactionRejectionReason(
|
|
1436
|
+
record: Record<string, unknown>,
|
|
1437
|
+
): "missing_required_reasoning_item" | null {
|
|
1438
|
+
// Classify the known provider protocol rejection without persisting the
|
|
1439
|
+
// message, referenced item ids, or arbitrary provider-owned fields.
|
|
1440
|
+
return typeof record.message === "string" &&
|
|
1441
|
+
record.message.length <= 1024 &&
|
|
1442
|
+
/^Item '[A-Za-z0-9_-]+' of type '[a-z_]+' was provided without its required 'reasoning' item: '[A-Za-z0-9_-]+'\.$/.test(
|
|
1443
|
+
record.message,
|
|
1444
|
+
)
|
|
1445
|
+
? "missing_required_reasoning_item"
|
|
1446
|
+
: null;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1378
1449
|
const COMPACTION_DIAGNOSTIC_FIELD_MAX_BYTES = 256;
|
|
1379
1450
|
const COMPACTION_DIAGNOSTIC_TRUNCATION_MARKER = "…[truncated]";
|
|
1380
1451
|
|
|
@@ -1548,6 +1619,8 @@ export type CodemodeTokenWriterSession = SandboxSessionLike;
|
|
|
1548
1619
|
|
|
1549
1620
|
const agentSkillSelections = new WeakMap<object, readonly EffectiveSkillSelection[]>();
|
|
1550
1621
|
const emptySkillSelections: readonly EffectiveSkillSelection[] = Object.freeze([]);
|
|
1622
|
+
const agentRuntimeSkillIndex = new WeakMap<object, readonly RuntimeSkillIndexEntry[]>();
|
|
1623
|
+
const emptyRuntimeSkillIndex: readonly RuntimeSkillIndexEntry[] = Object.freeze([]);
|
|
1551
1624
|
const agentInstructionInspection = new WeakMap<object, PersistentAgentInstructionInspection>();
|
|
1552
1625
|
const emptyInstructionInspection: PersistentAgentInstructionInspection = Object.freeze({
|
|
1553
1626
|
layers: Object.freeze([]),
|
|
@@ -1566,6 +1639,11 @@ export function effectiveSkillSelectionsForAgent(
|
|
|
1566
1639
|
return agentSkillSelections.get(agent) ?? emptySkillSelections;
|
|
1567
1640
|
}
|
|
1568
1641
|
|
|
1642
|
+
/** Sandbox-independent Skill index admitted for this agent. */
|
|
1643
|
+
export function runtimeSkillIndexForAgent(agent: object): readonly RuntimeSkillIndexEntry[] {
|
|
1644
|
+
return agentRuntimeSkillIndex.get(agent) ?? emptyRuntimeSkillIndex;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1569
1647
|
export function persistentAgentInstructionInspectionFor(
|
|
1570
1648
|
agent: object,
|
|
1571
1649
|
): PersistentAgentInstructionInspection {
|
|
@@ -1648,6 +1726,8 @@ const modelToolInvocation = new AsyncLocalStorage<ModelToolInvocation>();
|
|
|
1648
1726
|
const agentInputWaitYields = new WeakMap<object, InputWaitYield>();
|
|
1649
1727
|
|
|
1650
1728
|
export type BuildAgentOptions = {
|
|
1729
|
+
/** Live authority fence for intrinsic sandbox tools outside the MCP gateway. */
|
|
1730
|
+
authorizeAttemptExecution?: () => Promise<void> | void;
|
|
1651
1731
|
/** Trusted attempt-local wait receipt shared with prepared tools. */
|
|
1652
1732
|
inputWaitYield?: InputWaitYield;
|
|
1653
1733
|
model?: Model;
|
|
@@ -1873,10 +1953,8 @@ export type BuildAgentOptions = {
|
|
|
1873
1953
|
* executable tool catalog.
|
|
1874
1954
|
*/
|
|
1875
1955
|
skillActivations?: readonly RuntimeSkillActivation[];
|
|
1876
|
-
/**
|
|
1956
|
+
/** Host-owned descriptors and reader; mutually exclusive with skillActivations. */
|
|
1877
1957
|
skillCatalog?: readonly SkillCatalogDescriptor[];
|
|
1878
|
-
/** Shared reader serves configured Skills; filesystem discovery remains for repo Skills only. */
|
|
1879
|
-
serverSkillReading?: boolean;
|
|
1880
1958
|
/**
|
|
1881
1959
|
* Internal per-attempt cancellation boundary. The worker supplies Temporal's
|
|
1882
1960
|
* signal so an in-flight shell process is interrupted immediately instead of
|
|
@@ -2294,6 +2372,12 @@ export function hasCanonicalEditableArtifactToolSurface(
|
|
|
2294
2372
|
});
|
|
2295
2373
|
}
|
|
2296
2374
|
|
|
2375
|
+
const SkillReadToolInput = z.object({
|
|
2376
|
+
skill: z.string().min(1).max(512),
|
|
2377
|
+
listFiles: z.boolean().optional(),
|
|
2378
|
+
paths: z.array(z.string().min(1).max(1024)).min(1).max(128).optional(),
|
|
2379
|
+
});
|
|
2380
|
+
|
|
2297
2381
|
export function buildOpenGeniAgent(
|
|
2298
2382
|
settings: Settings,
|
|
2299
2383
|
resources: ResourceRef[],
|
|
@@ -2309,6 +2393,29 @@ export function buildOpenGeniAgent(
|
|
|
2309
2393
|
const editableArtifactToolsAvailable = hasCanonicalEditableArtifactToolSurface(
|
|
2310
2394
|
options.attemptToolCatalog,
|
|
2311
2395
|
);
|
|
2396
|
+
const hostSuppliedSkillCatalog = options.skillCatalog !== undefined;
|
|
2397
|
+
if (hostSuppliedSkillCatalog && options.skillActivations?.length) {
|
|
2398
|
+
throw new Error(
|
|
2399
|
+
"Supply either host Skill catalog/reader or runtime Skill activations, not both.",
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
// Site authoring needs filesystem execution; managed and connected compute
|
|
2403
|
+
// are equivalent. Reading supplied Skill files never needs either.
|
|
2404
|
+
const filesystemAvailable = (options.activeSandboxBackend ?? settings.sandboxBackend) !== "none";
|
|
2405
|
+
const skillComposition = composeRuntimeSkills(options.skillActivations ?? [], {
|
|
2406
|
+
editableArtifacts: !hostSuppliedSkillCatalog && editableArtifactToolsAvailable,
|
|
2407
|
+
sites: !hostSuppliedSkillCatalog && filesystemAvailable,
|
|
2408
|
+
videoGeneration: !hostSuppliedSkillCatalog && Boolean(options.videoGeneration),
|
|
2409
|
+
});
|
|
2410
|
+
const skillCatalog = hostSuppliedSkillCatalog
|
|
2411
|
+
? options.skillCatalog
|
|
2412
|
+
: skillComposition.index.length > 0
|
|
2413
|
+
? skillCatalogFromComposition(skillComposition)
|
|
2414
|
+
: undefined;
|
|
2415
|
+
const instructionOptions: BuildAgentOptions = {
|
|
2416
|
+
...options,
|
|
2417
|
+
...(skillCatalog !== undefined ? { skillCatalog } : {}),
|
|
2418
|
+
};
|
|
2312
2419
|
// Resolved per-turn gating. Each override defaults to today's settings-derived
|
|
2313
2420
|
// behaviour, so the legacy global-client callers (no resolved model) build the
|
|
2314
2421
|
// exact same agent as before; the multi-provider worker path passes the
|
|
@@ -2441,7 +2548,26 @@ export function buildOpenGeniAgent(
|
|
|
2441
2548
|
...(videoGenerationTool ? [videoGenerationTool] : []),
|
|
2442
2549
|
...(humanInputTool ? [humanInputTool] : []),
|
|
2443
2550
|
];
|
|
2444
|
-
const
|
|
2551
|
+
const embeddedSkillReadTool =
|
|
2552
|
+
!hostSuppliedSkillCatalog && skillComposition.artifacts.length > 0
|
|
2553
|
+
? agentTool({
|
|
2554
|
+
name: "skill_read",
|
|
2555
|
+
description:
|
|
2556
|
+
"Read Skill text without starting a sandbox. Omit paths to read SKILL.md; provide relative paths to read exactly those files, never implicitly adding SKILL.md. Set listFiles:true without paths to list relative paths only, with no file bodies. Use an id or name from the Skill index.",
|
|
2557
|
+
parameters: SkillReadToolInput,
|
|
2558
|
+
errorFunction: null,
|
|
2559
|
+
execute: (input) =>
|
|
2560
|
+
JSON.stringify(
|
|
2561
|
+
readRuntimeSkill(skillComposition, {
|
|
2562
|
+
skill: input.skill,
|
|
2563
|
+
...(input.paths !== undefined ? { paths: input.paths } : {}),
|
|
2564
|
+
...(input.listFiles !== undefined ? { listFiles: input.listFiles } : {}),
|
|
2565
|
+
}),
|
|
2566
|
+
),
|
|
2567
|
+
})
|
|
2568
|
+
: null;
|
|
2569
|
+
if (embeddedSkillReadTool) agentTools.push(embeddedSkillReadTool);
|
|
2570
|
+
const instructionInspection = inspectPersistentAgentInstructions(settings, instructionOptions);
|
|
2445
2571
|
const baseConfig = {
|
|
2446
2572
|
name: "OpenGeni Agent",
|
|
2447
2573
|
model: options.model ?? settings.openaiModel,
|
|
@@ -2504,6 +2630,8 @@ export function buildOpenGeniAgent(
|
|
|
2504
2630
|
const agent = new Agent(baseConfig);
|
|
2505
2631
|
if (options.inputWaitYield) agentInputWaitYields.set(agent, options.inputWaitYield);
|
|
2506
2632
|
agentInstructionInspection.set(agent, instructionInspection);
|
|
2633
|
+
agentSkillSelections.set(agent, skillComposition.selections);
|
|
2634
|
+
agentRuntimeSkillIndex.set(agent, skillComposition.index);
|
|
2507
2635
|
if (options.missingSessionTitleHint ?? options.genesisTitleHint) {
|
|
2508
2636
|
agentsNeedingGenesisTitleDirective.add(agent);
|
|
2509
2637
|
}
|
|
@@ -2532,26 +2660,6 @@ export function buildOpenGeniAgent(
|
|
|
2532
2660
|
return agent;
|
|
2533
2661
|
}
|
|
2534
2662
|
|
|
2535
|
-
const skillComposition = composeRuntimeSkills(
|
|
2536
|
-
options.serverSkillReading ? [] : (options.skillActivations ?? []),
|
|
2537
|
-
{
|
|
2538
|
-
editableArtifacts: !options.serverSkillReading && editableArtifactToolsAvailable,
|
|
2539
|
-
// Sites guidance is bundled capability metadata, not eager tool authority.
|
|
2540
|
-
// Tool discovery/execution remains governed by the lazy attempt gateway.
|
|
2541
|
-
sites:
|
|
2542
|
-
!options.serverSkillReading &&
|
|
2543
|
-
(options.activeSandboxBackend ?? settings.sandboxBackend) !== "selfhosted",
|
|
2544
|
-
// A connected machine owns its filesystem, and its session deliberately
|
|
2545
|
-
// does not materialize host-local lazy entries. Advertising this bundled
|
|
2546
|
-
// skill there makes load_skill report a path that does not exist. Keep the
|
|
2547
|
-
// executable tools (whose descriptions contain the full short workflow),
|
|
2548
|
-
// but expose the filesystem-backed helper only where it can be delivered.
|
|
2549
|
-
videoGeneration:
|
|
2550
|
-
!options.serverSkillReading &&
|
|
2551
|
-
Boolean(options.videoGeneration) &&
|
|
2552
|
-
options.activeSandboxBackend !== "selfhosted",
|
|
2553
|
-
},
|
|
2554
|
-
);
|
|
2555
2663
|
if (options.activeSandboxBackend === "selfhosted" && !options.sandboxWorkspaceRoot) {
|
|
2556
2664
|
throw new Error("A Connected Machine agent requires its reported workspace root");
|
|
2557
2665
|
}
|
|
@@ -2572,6 +2680,9 @@ export function buildOpenGeniAgent(
|
|
|
2572
2680
|
),
|
|
2573
2681
|
...(runAs ? { runAs } : {}),
|
|
2574
2682
|
capabilities: buildAgentCapabilitiesFromComposition(settings, skillComposition, {
|
|
2683
|
+
...(options.authorizeAttemptExecution
|
|
2684
|
+
? { authorizeAttemptExecution: options.authorizeAttemptExecution }
|
|
2685
|
+
: {}),
|
|
2575
2686
|
...(editableArtifactToolsAvailable ? { editableArtifactToolsAvailable: true } : {}),
|
|
2576
2687
|
...(options.videoGeneration ? { videoGenerationAvailable: true } : {}),
|
|
2577
2688
|
...repositoryWorkspaceSkillPathsOption(resources),
|
|
@@ -2595,6 +2706,7 @@ export function buildOpenGeniAgent(
|
|
|
2595
2706
|
}),
|
|
2596
2707
|
});
|
|
2597
2708
|
agentSkillSelections.set(agent, skillComposition.selections);
|
|
2709
|
+
agentRuntimeSkillIndex.set(agent, skillComposition.index);
|
|
2598
2710
|
if (options.inputWaitYield) agentInputWaitYields.set(agent, options.inputWaitYield);
|
|
2599
2711
|
agentInstructionInspection.set(agent, instructionInspection);
|
|
2600
2712
|
if (options.missingSessionTitleHint ?? options.genesisTitleHint) {
|
|
@@ -3306,6 +3418,7 @@ export function buildAgentCapabilities(
|
|
|
3306
3418
|
settings: Settings,
|
|
3307
3419
|
skillActivations: readonly RuntimeSkillActivation[] = [],
|
|
3308
3420
|
options: {
|
|
3421
|
+
authorizeAttemptExecution?: () => Promise<void> | void;
|
|
3309
3422
|
editableArtifactToolsAvailable?: boolean;
|
|
3310
3423
|
videoGenerationAvailable?: boolean;
|
|
3311
3424
|
workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
|
|
@@ -3335,6 +3448,7 @@ function buildAgentCapabilitiesFromComposition(
|
|
|
3335
3448
|
settings: Settings,
|
|
3336
3449
|
skillComposition: RuntimeSkillComposition,
|
|
3337
3450
|
options: {
|
|
3451
|
+
authorizeAttemptExecution?: () => Promise<void> | void;
|
|
3338
3452
|
editableArtifactToolsAvailable?: boolean;
|
|
3339
3453
|
videoGenerationAvailable?: boolean;
|
|
3340
3454
|
workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
|
|
@@ -3380,7 +3494,7 @@ function buildAgentCapabilitiesFromComposition(
|
|
|
3380
3494
|
? { configureTools: configureFilesystemTools }
|
|
3381
3495
|
: {}),
|
|
3382
3496
|
});
|
|
3383
|
-
if (options.structuredToolTransport === false) {
|
|
3497
|
+
if (options.structuredToolTransport === false || options.authorizeAttemptExecution) {
|
|
3384
3498
|
neutralizeStructuredToolTransport(filesystemCapability);
|
|
3385
3499
|
}
|
|
3386
3500
|
const caps: ReturnType<typeof Capabilities.default> = [
|
|
@@ -3389,11 +3503,6 @@ function buildAgentCapabilitiesFromComposition(
|
|
|
3389
3503
|
...(toolCancellation ? {} : { configureTools: withExecOpCorrelation }),
|
|
3390
3504
|
}),
|
|
3391
3505
|
];
|
|
3392
|
-
caps.push(
|
|
3393
|
-
skills({
|
|
3394
|
-
lazyFrom: skillComposition.lazySource,
|
|
3395
|
-
}),
|
|
3396
|
-
);
|
|
3397
3506
|
if (options.workspaceSkillPaths?.length) {
|
|
3398
3507
|
caps.push(
|
|
3399
3508
|
workspaceSkills(
|
|
@@ -3411,6 +3520,25 @@ function buildAgentCapabilitiesFromComposition(
|
|
|
3411
3520
|
);
|
|
3412
3521
|
}
|
|
3413
3522
|
}
|
|
3523
|
+
if (options.authorizeAttemptExecution) {
|
|
3524
|
+
for (const capability of caps) {
|
|
3525
|
+
const target = capability as unknown as { tools(): Tool<unknown>[] };
|
|
3526
|
+
const original = target.tools;
|
|
3527
|
+
target.tools = function () {
|
|
3528
|
+
return original.call(this).map((tool) => {
|
|
3529
|
+
if (tool.type !== "function") return tool;
|
|
3530
|
+
const invoke = tool.invoke;
|
|
3531
|
+
return {
|
|
3532
|
+
...tool,
|
|
3533
|
+
invoke: async (context, input, details) => {
|
|
3534
|
+
await options.authorizeAttemptExecution!();
|
|
3535
|
+
return invoke(context, input, details);
|
|
3536
|
+
},
|
|
3537
|
+
};
|
|
3538
|
+
});
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3414
3542
|
return caps;
|
|
3415
3543
|
}
|
|
3416
3544
|
|
|
@@ -3542,6 +3670,10 @@ export type PrepareToolsOptions = {
|
|
|
3542
3670
|
attemptToolDefinitions?: readonly AttemptToolDefinition[];
|
|
3543
3671
|
/** Host authorization applied after catalog/input validation and before execution. */
|
|
3544
3672
|
attemptToolAuthorize?: AttemptToolAuthorization;
|
|
3673
|
+
/** Live accepted-attempt fence, evaluated at execution rather than catalog
|
|
3674
|
+
* preparation. Includes model and Codemode calls and runs before consuming
|
|
3675
|
+
* connector approval authority. Does not alter catalog identity. */
|
|
3676
|
+
authorizeAttemptExecution?: () => Promise<void> | void;
|
|
3545
3677
|
/** Attempt-bound connector policy installed into the canonical gateway lifecycle. */
|
|
3546
3678
|
connectorActionPolicy?: ConnectorActionPolicyHooks;
|
|
3547
3679
|
/** Private connector identities for exact-name attempt-local tools. */
|
|
@@ -4387,10 +4519,29 @@ async function prepareAttemptToolEnvironment(
|
|
|
4387
4519
|
options.connectorActionPolicy,
|
|
4388
4520
|
);
|
|
4389
4521
|
const subjectId = options.subjectId ?? "worker:mcp-model";
|
|
4522
|
+
const guardedDefinitions = options.authorizeAttemptExecution
|
|
4523
|
+
? definitions.map((definition) => ({
|
|
4524
|
+
...definition,
|
|
4525
|
+
lifecycle: {
|
|
4526
|
+
prepare: async (
|
|
4527
|
+
input: Parameters<NonNullable<AttemptToolDefinition["lifecycle"]>["prepare"]>[0],
|
|
4528
|
+
) => {
|
|
4529
|
+
const prior = await definition.lifecycle?.prepare(input);
|
|
4530
|
+
return {
|
|
4531
|
+
begin: async () => {
|
|
4532
|
+
await options.authorizeAttemptExecution!();
|
|
4533
|
+
await prior?.begin?.();
|
|
4534
|
+
},
|
|
4535
|
+
...(prior?.complete ? { complete: prior.complete } : {}),
|
|
4536
|
+
};
|
|
4537
|
+
},
|
|
4538
|
+
},
|
|
4539
|
+
}))
|
|
4540
|
+
: definitions;
|
|
4390
4541
|
const environment = createAttemptToolEnvironment({
|
|
4391
4542
|
scope,
|
|
4392
4543
|
generation: options.attemptToolCatalogGeneration ?? 1,
|
|
4393
|
-
definitions,
|
|
4544
|
+
definitions: guardedDefinitions,
|
|
4394
4545
|
confirmModelApproval: ({ modelName, subjectId: callerSubjectId }) =>
|
|
4395
4546
|
callerSubjectId === subjectId &&
|
|
4396
4547
|
activeModelToolInvocation(modelName)?.approvalConfirmed === true,
|
|
@@ -31,9 +31,6 @@ const ALWAYS_VISIBLE_BASE_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
|
31
31
|
"view_image",
|
|
32
32
|
// A plain function tool on Chat Completions; Responses uses type apply_patch.
|
|
33
33
|
"apply_patch",
|
|
34
|
-
// The SDK skills capability prints the skill index in the instructions and
|
|
35
|
-
// mandates this call before any SKILL.md read.
|
|
36
|
-
"load_skill",
|
|
37
34
|
// The server-backed reader needs neither sandbox setup nor tool search.
|
|
38
35
|
"skill_read",
|
|
39
36
|
"request_human_input",
|
package/src/model-input.ts
CHANGED
|
@@ -49,7 +49,7 @@ export const stripProviderItemIdsFilter: CallModelInputFilter = ({ modelData })
|
|
|
49
49
|
return projected ? { ...modelData, input: projected } : modelData;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
function stripProviderItemId(item: AgentInputItem): AgentInputItem {
|
|
52
|
+
export function stripProviderItemId(item: AgentInputItem): AgentInputItem {
|
|
53
53
|
if (!item || typeof item !== "object" || !("id" in item)) return item;
|
|
54
54
|
const { id: _id, ...rest } = item as Record<string, unknown>;
|
|
55
55
|
return rest as AgentInputItem;
|
package/src/run-events.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
approvalIdentifier,
|
|
5
5
|
RequestHumanInteractionToolInput,
|
|
6
6
|
RequestHumanInputToolInput,
|
|
7
|
+
canonicalSkillReviewQuestion,
|
|
7
8
|
sessionEventMediaPreview,
|
|
8
9
|
sessionEventMediaPreviewFromDataUrl,
|
|
9
10
|
type SessionEventMediaPreview,
|
|
@@ -690,6 +691,28 @@ export function serializeHumanInputRequests(
|
|
|
690
691
|
throw new Error("Human-input interruption is missing a stable tool-call identity");
|
|
691
692
|
}
|
|
692
693
|
const input = RequestHumanInputToolInput.parse(interruptionArguments(item));
|
|
694
|
+
const reviews = input.questions.filter((question) => question.skillReview);
|
|
695
|
+
if (reviews.length > 0) {
|
|
696
|
+
if (input.questions.length !== 1) {
|
|
697
|
+
throw new Error("Skill review requires one dedicated human-input question");
|
|
698
|
+
}
|
|
699
|
+
const question = reviews[0]!;
|
|
700
|
+
const canonical = canonicalSkillReviewQuestion(question);
|
|
701
|
+
// Normalize only known wire differences, never turn misleading text
|
|
702
|
+
// into a trusted review based solely on a model-supplied reference.
|
|
703
|
+
// The DB still binds that reference to the receipt and live human.
|
|
704
|
+
if (!canonical) {
|
|
705
|
+
throw new Error("Skill review must use the exact host-owned confirmation presentation");
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
toolCallId,
|
|
709
|
+
input: {
|
|
710
|
+
...input,
|
|
711
|
+
questions: [canonical],
|
|
712
|
+
allowSkip: false,
|
|
713
|
+
},
|
|
714
|
+
};
|
|
715
|
+
}
|
|
693
716
|
return {
|
|
694
717
|
toolCallId,
|
|
695
718
|
input: {
|