@opengeni/runtime 0.13.13 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Tool, Computer, AgentInputItem, Model, MCPServer, ModelProvider, Agent,
3
3
  export { MaxTurnsExceededError, OpenAIChatCompletionsModel, OpenAIResponsesModel } from '@openai/agents';
4
4
  import { Settings, ResolvedModelProvider, ConfiguredModel, ModelProviderApi } from '@opengeni/config';
5
5
  export { collectSandboxEnvironment, parseExposedPorts } from '@opengeni/config';
6
- import { HumanInputResponse, ReasoningEffort, GitCredentialProvider, GitCredentialTransport, SessionEventType, ResourceRef, ToolRef, Permission, McpServerConnectionRef, ToolAuthNeededPayload, RequestHumanInputToolInput } from '@opengeni/contracts';
6
+ import { HumanInputResponse, ReasoningEffort, GitCredentialProvider, GitCredentialTransport, SessionEventType, ResourceRef, ToolRef, Permission, FirstPartyMcpToolName, McpServerConnectionRef, ToolAuthNeededPayload, RequestHumanInputToolInput } from '@opengeni/contracts';
7
7
  export { CAPABILITY_DESCRIPTORS, CapabilityDescriptor, DESKTOP_STREAM_PORT, StreamTokenPayload, StreamTokenPayload as StreamTokenPayloadType, TERMINAL_STREAM_PORT } from '@opengeni/contracts';
8
8
  import { SandboxSessionLike, Capability, SandboxSessionState, Manifest, Capabilities, LocalDirLazySkillSource, SandboxClient } from '@openai/agents/sandbox';
9
9
  import OpenAI from 'openai';
@@ -40,8 +40,6 @@ declare const USER_MESSAGE_TRUNCATION_MARKER = "\n[... middle truncated for cont
40
40
  declare function isUserMessage(item: unknown): boolean;
41
41
  /** True for our synthetic compaction summary item. */
42
42
  declare function isCompactionSummary(item: unknown): boolean;
43
- /** Platform-authored system context exists for one inference and is never persisted. */
44
- declare function isEphemeralInternalContext(item: unknown): boolean;
45
43
  /** Serialized-item estimate for pre-call accounting and retained user budgets. */
46
44
  declare function estimateItemTokens(item: CompactionItem): number;
47
45
  declare function estimateTokens(items: readonly CompactionItem[]): number;
@@ -371,6 +369,11 @@ declare class ComputerUseCapability extends Capability {
371
369
  private hostedComputerTool;
372
370
  }
373
371
 
372
+ type WorkspaceSkillSearchPath = Readonly<{
373
+ path: string;
374
+ source: string;
375
+ }>;
376
+
374
377
  /**
375
378
  * Read-path sanitizer for replayed conversation history (issue: orphaned
376
379
  * tool outputs brick a session).
@@ -838,7 +841,7 @@ type ToolspaceTokenWriterSession = SandboxSessionLike;
838
841
  type EffectiveSkillSelection = Readonly<{
839
842
  id: string;
840
843
  name: string;
841
- source: "bundled" | "library" | "pack";
844
+ source: "bundled" | "library" | "pack" | "session";
842
845
  version: string | null;
843
846
  contentSha256: string | null;
844
847
  reason: string;
@@ -892,6 +895,7 @@ type BuildAgentOptions = {
892
895
  sessionInstructions?: string;
893
896
  turnInstructions?: string;
894
897
  packSkills?: PackSkill[];
898
+ sessionSkills?: PackSkill[];
895
899
  skillLibrarySkills?: PackSkill[];
896
900
  skillLibrarySelections?: EffectiveSkillSelection[];
897
901
  /**
@@ -913,7 +917,7 @@ type PackSkillFile = {
913
917
  };
914
918
  type PackSkill = {
915
919
  name: string;
916
- description?: string | null;
920
+ description?: string | null | undefined;
917
921
  files: PackSkillFile[];
918
922
  };
919
923
  /**
@@ -1066,6 +1070,8 @@ declare function buildOpenGeniAgent(settings: Settings, resources: ResourceRef[]
1066
1070
  declare function withStructuredViewImageFunctionResults(tools: Tool<unknown>[]): Tool<unknown>[];
1067
1071
  declare function buildAgentCapabilities(settings: Settings, packSkills: PackSkill[], options?: {
1068
1072
  skillLibrarySkills?: PackSkill[];
1073
+ sessionSkills?: PackSkill[];
1074
+ workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
1069
1075
  structuredToolTransport?: boolean;
1070
1076
  computerToolMode?: ComputerToolMode;
1071
1077
  onComputerUseReady?: (session: SandboxSessionLike) => Promise<void>;
@@ -1087,7 +1093,9 @@ type PrepareToolsOptions = {
1087
1093
  executionGeneration?: number;
1088
1094
  subjectId?: string;
1089
1095
  subjectLabel?: string;
1096
+ credentialSubjectId?: string;
1090
1097
  firstPartyPermissions?: Permission[];
1098
+ firstPartyTools?: FirstPartyMcpToolName[];
1091
1099
  resolveCredential?: (input: ResolveConnectionCredentialInput) => Promise<ResolveConnectionCredentialResult>;
1092
1100
  onAuthNeeded?: (payload: ToolAuthNeededPayload) => Promise<void> | void;
1093
1101
  /** Injectable final MCP transport for tests and embedded hosts. */
@@ -1303,6 +1311,9 @@ declare function modelResponseUsageFromResponse(response: unknown): ModelRespons
1303
1311
  declare function serializeApprovals(interruptions: unknown[]): unknown[];
1304
1312
  declare function serializeHumanInputRequests(interruptions: unknown[]): SerializedHumanInputInterruption[];
1305
1313
  declare function buildManifest(settings: Settings, resources: ResourceRef[], environment?: Record<string, string>, fileResourceDownloads?: SandboxFileDownload[]): Manifest;
1314
+ declare function repositoryWorkspaceSkillPathsOption(resources: readonly ResourceRef[]): {
1315
+ workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
1316
+ };
1306
1317
  type SandboxLifecycleHookPhase = "beforeAgentStart";
1307
1318
  type SandboxLifecycleCommandRunner = (session: TurnSandboxCommandSession, args: TurnSandboxCommandArgs) => Promise<unknown>;
1308
1319
  type SandboxLifecycleHookContext = {
@@ -1446,4 +1457,4 @@ declare function azureOpenAIDefaultQuery(settings: Pick<Settings, "azureOpenaiAp
1446
1457
  */
1447
1458
  declare function lazySkillSourceWithPackSkills(packSkills: PackSkill[], skillLibrarySkills?: PackSkill[]): LocalDirLazySkillSource;
1448
1459
 
1449
- export { type AgentSegmentInput, type BuildAgentOptions, COMPACTION_PROMPT, COMPACTION_SUMMARY_MARKER, COMPACT_USER_MESSAGE_MAX_TOKENS, CodexSubscriptionUnavailableError, type CompactionDecision, type CompactionItem, CompactionNeededError, CompactionProviderResponseError, ComputerActionError, ComputerReadOnlyError, type ComputerToolMode, ComputerUnavailableError, type ComputerUseArgs, ComputerUseCapability, type ConnectedMcpServerBatches, type ContextRobustnessFilterOptions, DEFAULT_COMPACTION_THRESHOLD_RATIO, type EffectiveSkillSelection, EmptyCompactionSummaryError, GENESIS_TITLE_DIRECTIVE, type GitCredentialBindingSeed, type GitCredentialTokenWriterSession, type GitTokenSeeds, HUMAN_INPUT_TOOL_NAME, type HistoryItem, MAX_COMPACTION_THRESHOLD_RATIO, MAX_MODEL_USAGE_TOKEN_COUNT, MIN_COMPACTION_THRESHOLD_RATIO, type ModelCallUsageInput, type ModelCallUsageNormalization, type ModelCallUsageTelemetry, type ModelResponseUsage, MultiProviderModelProvider, type NormalizedRuntimeEvent, type OpenGeniRuntime, type PackSkill, type PackSkillFile, type PersistentSessionSettings, type PrepareInputOptions, type PrepareToolsOptions, type PreparedAgentInput, type PreparedAgentTools, type PreparedCompactionPromptInput, type ProductionRuntimeOverrides, type ResolveConnectionCredentialInput, type ResolveConnectionCredentialResult, type RigInstructionsContext, type RigSetupDescriptor, type RunAgentStreamOptions, RunCredentialSessionReady, RuntimeMetricsHooks, SUMMARY_BUFFER_TOKENS, SUMMARY_PREFIX, SandboxComputer, type SandboxComputerOptions, type SandboxFileDownload, type SandboxFileDownloadFailure, type SandboxFileDownloadMaterializationResult, type SandboxLifecycleCommandRunner, type SandboxLifecycleHook, type SandboxLifecycleHookContext, type SandboxLifecycleHookPhase, type SerializedHumanInputInterruption, TOOLSPACE_PROGRAMMATIC_DIRECTIVE, type ToolspaceTokenWriterSession, type TurnSandboxCommandArgs, TurnSandboxCommandCancelledError, type TurnSandboxCommandSession, type TurnToolCancellationController, type TurnToolCancellationFence, USER_MESSAGE_TRUNCATION_MARKER, type WorkspaceEnvironmentContext, WorkspaceModelPolicyBlockedError, agentsErrorRunState, appendGenesisTitleDirective, appendGitCredentialBindingInstructions, appendPersistentSessionSettings, appendSessionInstructions, appendToolspaceInstructions, appendTurnInstructions, appendWorkspaceMemory, applyMissingManifestEntries, azureCliLoginCommand, azureOpenAIDefaultQuery, boundModelToolOutputsFilterForSettings, buildAgentCapabilities, buildCompactionPromptInput, buildCompactionReplacementHistory, buildManifest, buildModelInstance, buildOpenAIClientFromSettings, buildOpenGeniAgent, buildProviderClient, buildSummaryItem, callModelInputFilterForSettings, clampCompactionThresholdRatio, compactionProviderFailureDiagnostics, compactionReplacementFingerprint, compactionResponseDiagnostics, compactionThresholdTokens, composeAgentInstructions, computerUse, configureOpenAI, configureRuntimeMetricsHooks, connectMcpServersInBatches, contextRobustnessFilterForSettings, coreInstructions, createProductionAgentRuntime, createTurnToolCancellationController, decideCompaction, effectiveSkillSelectionsForAgent, elideSupersededViewImagePairs, elideSupersededViewImagesFilter, ensureReadableStreamFrom, estimateCompleteModelInput, estimateItemTokens, estimateSerializedValueTokens, estimateTokens, extractResponseOutputText, findCompactionNeededError, gitCredentialBindingHash, gitCredentialBindingTokenRefreshCommand, gitProviderTokenRefreshCommand, hasModelGeneratedItem, isCompactionSummary, isEphemeralInternalContext, isUserMessage, latestCompactionReplacementFingerprint, lazySkillSourceWithPackSkills, manifestEnvironmentDrift, materializeSandboxFileDownloads, maxTurnsExceededRunState, mcpToolErrorOutput, modelCallUsageTelemetry, modelResponseUsageFromResponse, modelResponseUsageFromSdkEvent, modelUsageTokenCountOrNull, neutralizeToolSearchItemsInSerializedRunState, normalizeComputerCallsFilter, normalizeModelCallUsage, normalizeSdkEvent, normalizeToolOutputForEvent, oneShotGenesisTitleInputFilter, pinProvidedSessionManifestEnvironment, prefixedMcpToolName, prepareAgentTools, prepareCompactionPromptInput, prepareRunInput, refreshGitCredentialBindingTokenFiles, refreshGitProviderTokenFiles, refreshToolspaceTokenFile, renderCompactionPromptInputForChat, repositoryCloneCommand, repositoryUsesSandboxClone, resolveTurnModel, rigInstructions, rigSetupScriptCommand, runAgentStream, runAzureCliLoginHook, runBeforeAgentStartHooks, runOwnedSandboxSetup, runRepositoryCloneHook, runRigSetupHook, runToolspaceTokenSeedHook, sandboxCommandExitCode, sandboxCommandOutput, sandboxCommandStillRunning, sandboxFileDownloadFailureNote, sandboxFileDownloadsForAgent, sandboxLifecycleHooksForIds, sandboxRunAs, sanitizeHistoryItemsForModel, serializeApprovals, serializeHumanInputRequests, stripProviderItemIdsFilter, stripReasoningEncryptedContent, stripReasoningIdentityFromSerializedRunState, summarizeForCompaction, toolspaceTokenSeedCommand, withManifestRefreshOnResume, withSandboxFileDownloads, withSandboxLifecycleHooks, withStructuredViewImageFunctionResults, workspaceEnvironmentInstructions };
1460
+ export { type AgentSegmentInput, type BuildAgentOptions, COMPACTION_PROMPT, COMPACTION_SUMMARY_MARKER, COMPACT_USER_MESSAGE_MAX_TOKENS, CodexSubscriptionUnavailableError, type CompactionDecision, type CompactionItem, CompactionNeededError, CompactionProviderResponseError, ComputerActionError, ComputerReadOnlyError, type ComputerToolMode, ComputerUnavailableError, type ComputerUseArgs, ComputerUseCapability, type ConnectedMcpServerBatches, type ContextRobustnessFilterOptions, DEFAULT_COMPACTION_THRESHOLD_RATIO, type EffectiveSkillSelection, EmptyCompactionSummaryError, GENESIS_TITLE_DIRECTIVE, type GitCredentialBindingSeed, type GitCredentialTokenWriterSession, type GitTokenSeeds, HUMAN_INPUT_TOOL_NAME, type HistoryItem, MAX_COMPACTION_THRESHOLD_RATIO, MAX_MODEL_USAGE_TOKEN_COUNT, MIN_COMPACTION_THRESHOLD_RATIO, type ModelCallUsageInput, type ModelCallUsageNormalization, type ModelCallUsageTelemetry, type ModelResponseUsage, MultiProviderModelProvider, type NormalizedRuntimeEvent, type OpenGeniRuntime, type PackSkill, type PackSkillFile, type PersistentSessionSettings, type PrepareInputOptions, type PrepareToolsOptions, type PreparedAgentInput, type PreparedAgentTools, type PreparedCompactionPromptInput, type ProductionRuntimeOverrides, type ResolveConnectionCredentialInput, type ResolveConnectionCredentialResult, type RigInstructionsContext, type RigSetupDescriptor, type RunAgentStreamOptions, RunCredentialSessionReady, RuntimeMetricsHooks, SUMMARY_BUFFER_TOKENS, SUMMARY_PREFIX, SandboxComputer, type SandboxComputerOptions, type SandboxFileDownload, type SandboxFileDownloadFailure, type SandboxFileDownloadMaterializationResult, type SandboxLifecycleCommandRunner, type SandboxLifecycleHook, type SandboxLifecycleHookContext, type SandboxLifecycleHookPhase, type SerializedHumanInputInterruption, TOOLSPACE_PROGRAMMATIC_DIRECTIVE, type ToolspaceTokenWriterSession, type TurnSandboxCommandArgs, TurnSandboxCommandCancelledError, type TurnSandboxCommandSession, type TurnToolCancellationController, type TurnToolCancellationFence, USER_MESSAGE_TRUNCATION_MARKER, type WorkspaceEnvironmentContext, WorkspaceModelPolicyBlockedError, agentsErrorRunState, appendGenesisTitleDirective, appendGitCredentialBindingInstructions, appendPersistentSessionSettings, appendSessionInstructions, appendToolspaceInstructions, appendTurnInstructions, appendWorkspaceMemory, applyMissingManifestEntries, azureCliLoginCommand, azureOpenAIDefaultQuery, boundModelToolOutputsFilterForSettings, buildAgentCapabilities, buildCompactionPromptInput, buildCompactionReplacementHistory, buildManifest, buildModelInstance, buildOpenAIClientFromSettings, buildOpenGeniAgent, buildProviderClient, buildSummaryItem, callModelInputFilterForSettings, clampCompactionThresholdRatio, compactionProviderFailureDiagnostics, compactionReplacementFingerprint, compactionResponseDiagnostics, compactionThresholdTokens, composeAgentInstructions, computerUse, configureOpenAI, configureRuntimeMetricsHooks, connectMcpServersInBatches, contextRobustnessFilterForSettings, coreInstructions, createProductionAgentRuntime, createTurnToolCancellationController, decideCompaction, effectiveSkillSelectionsForAgent, elideSupersededViewImagePairs, elideSupersededViewImagesFilter, ensureReadableStreamFrom, estimateCompleteModelInput, estimateItemTokens, estimateSerializedValueTokens, estimateTokens, extractResponseOutputText, findCompactionNeededError, gitCredentialBindingHash, gitCredentialBindingTokenRefreshCommand, gitProviderTokenRefreshCommand, hasModelGeneratedItem, isCompactionSummary, isUserMessage, latestCompactionReplacementFingerprint, lazySkillSourceWithPackSkills, manifestEnvironmentDrift, materializeSandboxFileDownloads, maxTurnsExceededRunState, mcpToolErrorOutput, modelCallUsageTelemetry, modelResponseUsageFromResponse, modelResponseUsageFromSdkEvent, modelUsageTokenCountOrNull, neutralizeToolSearchItemsInSerializedRunState, normalizeComputerCallsFilter, normalizeModelCallUsage, normalizeSdkEvent, normalizeToolOutputForEvent, oneShotGenesisTitleInputFilter, pinProvidedSessionManifestEnvironment, prefixedMcpToolName, prepareAgentTools, prepareCompactionPromptInput, prepareRunInput, refreshGitCredentialBindingTokenFiles, refreshGitProviderTokenFiles, refreshToolspaceTokenFile, renderCompactionPromptInputForChat, repositoryCloneCommand, repositoryUsesSandboxClone, repositoryWorkspaceSkillPathsOption, resolveTurnModel, rigInstructions, rigSetupScriptCommand, runAgentStream, runAzureCliLoginHook, runBeforeAgentStartHooks, runOwnedSandboxSetup, runRepositoryCloneHook, runRigSetupHook, runToolspaceTokenSeedHook, sandboxCommandExitCode, sandboxCommandOutput, sandboxCommandStillRunning, sandboxFileDownloadFailureNote, sandboxFileDownloadsForAgent, sandboxLifecycleHooksForIds, sandboxRunAs, sanitizeHistoryItemsForModel, serializeApprovals, serializeHumanInputRequests, stripProviderItemIdsFilter, stripReasoningEncryptedContent, stripReasoningIdentityFromSerializedRunState, summarizeForCompaction, toolspaceTokenSeedCommand, withManifestRefreshOnResume, withSandboxFileDownloads, withSandboxLifecycleHooks, withStructuredViewImageFunctionResults, workspaceEnvironmentInstructions };
package/dist/index.js CHANGED
@@ -150,6 +150,7 @@ import {
150
150
  serializeEstablishedSandboxEnvelope,
151
151
  serializeReplacementSandboxEnvelope,
152
152
  setSelfhostedApplyDiff,
153
+ shellToolspacePath,
153
154
  startRecording,
154
155
  stopRecording,
155
156
  stripExecBanner,
@@ -175,7 +176,7 @@ import {
175
176
  withToolspaceTokenEnvironment,
176
177
  withToolspaceTokenSession,
177
178
  wrapCapabilityToolsForTurnCancellation
178
- } from "./chunk-3NUSY22C.js";
179
+ } from "./chunk-HHWIZHQM.js";
179
180
  import {
180
181
  getSkillLibraryEntry,
181
182
  isSkillLibraryEntryId,
@@ -267,6 +268,7 @@ import {
267
268
  approvalIdentifier,
268
269
  CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2,
269
270
  DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
271
+ DEFAULT_FIRST_PARTY_MCP_TOOLS,
270
272
  assertUniqueResourceMountPaths,
271
273
  gitCredentialBindingIdForRepository,
272
274
  gitCredentialProviderForRepository,
@@ -6422,7 +6424,7 @@ import {
6422
6424
  codexSubscriptionFetch
6423
6425
  } from "@opengeni/codex";
6424
6426
  import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
6425
- import { createHash as createHash2 } from "crypto";
6427
+ import { createHash as createHash3 } from "crypto";
6426
6428
  import { dirname, isAbsolute, join, posix as posixPath, relative } from "path";
6427
6429
  import { fileURLToPath } from "url";
6428
6430
 
@@ -7225,9 +7227,6 @@ function isUserMessage(item) {
7225
7227
  function isCompactionSummary(item) {
7226
7228
  return isUserMessage(item) && item[COMPACTION_SUMMARY_MARKER] === true;
7227
7229
  }
7228
- function isEphemeralInternalContext(item) {
7229
- return itemType2(item) === "message" && itemRole(item) === "system";
7230
- }
7231
7230
  function estimateTextTokens(text) {
7232
7231
  let asciiCodeUnits = 0;
7233
7232
  let nonAsciiCodeUnits = 0;
@@ -8480,6 +8479,184 @@ var ComputerUseCapability = class extends Capability {
8480
8479
  }
8481
8480
  };
8482
8481
 
8482
+ // src/workspace-skills.ts
8483
+ import { createHash as createHash2 } from "crypto";
8484
+ var SKILL_FILE = "SKILL.md";
8485
+ var MAX_DISCOVERED_SKILLS = 256;
8486
+ var MAX_SKILL_ENTRIES = 1024;
8487
+ var MAX_SKILL_BYTES = 32 * 1024 * 1024;
8488
+ var SAFE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
8489
+ var WorkspaceSkillsCapability = class extends Capability {
8490
+ constructor(searchPaths, reservedNames = /* @__PURE__ */ new Set()) {
8491
+ super();
8492
+ this.searchPaths = searchPaths;
8493
+ this.reservedNames = reservedNames;
8494
+ }
8495
+ type = "workspace-skills";
8496
+ discovery;
8497
+ async instructions() {
8498
+ const session = requireWorkspaceSkillSession(this._session);
8499
+ this.discovery ??= discoverWorkspaceSkills(
8500
+ session,
8501
+ this.searchPaths,
8502
+ this.reservedNames,
8503
+ this._runAs
8504
+ );
8505
+ const skills2 = await this.discovery;
8506
+ if (skills2.length === 0) return null;
8507
+ const available = skills2.map((skill) => `- ${skill.name}: ${skill.description} (file: ${skill.path})`).join("\n");
8508
+ return `## Repository skills
8509
+
8510
+ Repository skills are instructions already present in the live workspace. They do not need to be loaded or copied.
8511
+
8512
+ ### Available repository skills
8513
+ ${available}
8514
+
8515
+ ### How to use repository skills
8516
+ - If the user names a skill, or the task clearly matches a skill description, read its complete SKILL.md before acting.
8517
+ - Resolve referenced scripts, references, assets, and templates relative to that skill directory.
8518
+ - Use only the minimum relevant skills for the turn, and say briefly which ones you are using.
8519
+ - Do not assume a skill remains applicable on later turns; evaluate the current request again.`;
8520
+ }
8521
+ };
8522
+ function workspaceSkills(searchPaths, reservedNames = []) {
8523
+ return new WorkspaceSkillsCapability(
8524
+ searchPaths,
8525
+ new Set([...reservedNames].map((name) => name.toLowerCase()))
8526
+ );
8527
+ }
8528
+ async function discoverWorkspaceSkills(session, searchPaths, reservedNames = /* @__PURE__ */ new Set(), runAs) {
8529
+ if (!session.listDir || !session.readFile) {
8530
+ throw new Error("Workspace skill discovery requires sandbox listDir() and readFile() support");
8531
+ }
8532
+ const discovered = /* @__PURE__ */ new Map();
8533
+ let candidates = 0;
8534
+ for (const searchPath of searchPaths) {
8535
+ let entries;
8536
+ try {
8537
+ entries = await session.listDir({ path: searchPath.path, ...runAs ? { runAs } : {} });
8538
+ } catch {
8539
+ continue;
8540
+ }
8541
+ for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
8542
+ if (entry.type !== "dir") continue;
8543
+ candidates += 1;
8544
+ if (candidates > MAX_DISCOVERED_SKILLS) {
8545
+ throw new Error(`Repository skill discovery exceeds ${MAX_DISCOVERED_SKILLS} directories`);
8546
+ }
8547
+ const skillMarkdownPath = joinWorkspacePath(entry.path, SKILL_FILE);
8548
+ let markdown;
8549
+ try {
8550
+ const content = await session.readFile({
8551
+ path: skillMarkdownPath,
8552
+ ...runAs ? { runAs } : {}
8553
+ });
8554
+ markdown = typeof content === "string" ? content : new TextDecoder().decode(content);
8555
+ } catch {
8556
+ continue;
8557
+ }
8558
+ const frontmatter = parseSkillFrontmatter(markdown);
8559
+ const name = frontmatter.name?.trim() || entry.name;
8560
+ if (name.length > 64 || !SAFE_SKILL_NAME.test(name)) {
8561
+ throw new Error(`Repository skill has an invalid name: ${name.slice(0, 64)}`);
8562
+ }
8563
+ const description = frontmatter.description?.trim() || "No description provided.";
8564
+ if (description.length > 2048 || /[\r\n]/.test(description)) {
8565
+ throw new Error(`Repository skill "${name}" has an invalid description`);
8566
+ }
8567
+ const key = name.toLowerCase();
8568
+ if (reservedNames.has(key)) {
8569
+ throw new Error(`Workspace skill "${name}" conflicts with a configured OpenGeni skill`);
8570
+ }
8571
+ const candidate = {
8572
+ name,
8573
+ description,
8574
+ path: skillMarkdownPath,
8575
+ fingerprint: await fingerprintWorkspaceDirectory(session, entry.path, runAs),
8576
+ source: searchPath.source
8577
+ };
8578
+ const existing = discovered.get(key);
8579
+ if (!existing) {
8580
+ discovered.set(key, candidate);
8581
+ continue;
8582
+ }
8583
+ if (existing.fingerprint !== candidate.fingerprint) {
8584
+ throw new Error(
8585
+ `Workspace skill "${name}" has conflicting definitions in ${existing.source} and ${candidate.source}`
8586
+ );
8587
+ }
8588
+ }
8589
+ }
8590
+ return [...discovered.values()].sort((left, right) => left.name.localeCompare(right.name));
8591
+ }
8592
+ async function fingerprintWorkspaceDirectory(session, root, runAs) {
8593
+ const hash = createHash2("sha256");
8594
+ let entryCount = 0;
8595
+ let byteCount = 0;
8596
+ async function visit(path, relativePath) {
8597
+ const entries = await session.listDir({ path, ...runAs ? { runAs } : {} });
8598
+ for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
8599
+ entryCount += 1;
8600
+ if (entryCount > MAX_SKILL_ENTRIES) {
8601
+ throw new Error(`Workspace skill exceeds ${MAX_SKILL_ENTRIES} filesystem entries`);
8602
+ }
8603
+ const childRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
8604
+ hash.update(entry.type);
8605
+ hash.update("\0");
8606
+ hash.update(childRelativePath);
8607
+ hash.update("\0");
8608
+ if (entry.type === "dir") {
8609
+ await visit(entry.path, childRelativePath);
8610
+ continue;
8611
+ }
8612
+ if (entry.type !== "file") continue;
8613
+ const content = await session.readFile({
8614
+ path: entry.path,
8615
+ ...runAs ? { runAs } : {}
8616
+ });
8617
+ const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
8618
+ byteCount += bytes.byteLength;
8619
+ if (byteCount > MAX_SKILL_BYTES) {
8620
+ throw new Error(`Workspace skill exceeds ${MAX_SKILL_BYTES} bytes`);
8621
+ }
8622
+ hash.update(bytes);
8623
+ hash.update("\0");
8624
+ }
8625
+ }
8626
+ await visit(root, "");
8627
+ return hash.digest("hex");
8628
+ }
8629
+ function parseSkillFrontmatter(markdown) {
8630
+ const lines = markdown.split(/\r?\n/);
8631
+ if (lines[0]?.trim() !== "---") return {};
8632
+ const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
8633
+ if (end === -1) return {};
8634
+ const values = {};
8635
+ for (const line of lines.slice(1, end)) {
8636
+ const separator = line.indexOf(":");
8637
+ if (separator === -1) continue;
8638
+ const key = line.slice(0, separator).trim();
8639
+ if (key !== "name" && key !== "description") continue;
8640
+ values[key] = unquote(line.slice(separator + 1).trim());
8641
+ }
8642
+ return values;
8643
+ }
8644
+ function unquote(value) {
8645
+ if (value.length >= 2 && value[0] === value[value.length - 1] && (value[0] === '"' || value[0] === "'")) {
8646
+ return value.slice(1, -1);
8647
+ }
8648
+ return value;
8649
+ }
8650
+ function joinWorkspacePath(parent, child) {
8651
+ return `${parent.replace(/\/+$/, "")}/${child}`;
8652
+ }
8653
+ function requireWorkspaceSkillSession(session) {
8654
+ if (!session) {
8655
+ throw new Error('capability "workspace-skills" used before bind(session)');
8656
+ }
8657
+ return session;
8658
+ }
8659
+
8483
8660
  // src/usage-telemetry.ts
8484
8661
  var MAX_MODEL_USAGE_TOKEN_COUNT = 1e9;
8485
8662
  function modelUsageTokenCountOrNull(value) {
@@ -9574,6 +9751,8 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
9574
9751
  ...runAs ? { runAs } : {},
9575
9752
  capabilities: buildAgentCapabilities(settings, options.packSkills ?? [], {
9576
9753
  ...options.skillLibrarySkills?.length ? { skillLibrarySkills: options.skillLibrarySkills } : {},
9754
+ ...options.sessionSkills?.length ? { sessionSkills: options.sessionSkills } : {},
9755
+ ...repositoryWorkspaceSkillPathsOption(resources),
9577
9756
  ...options.structuredToolTransport !== void 0 ? { structuredToolTransport: options.structuredToolTransport } : {},
9578
9757
  ...options.computerToolMode !== void 0 ? { computerToolMode: options.computerToolMode } : {},
9579
9758
  ...options.onComputerUseReady ? { onComputerUseReady: options.onComputerUseReady } : {},
@@ -9587,7 +9766,8 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
9587
9766
  effectiveSkillSelections(
9588
9767
  options.skillLibrarySelections ?? [],
9589
9768
  options.skillLibrarySkills ?? [],
9590
- options.packSkills ?? []
9769
+ options.packSkills ?? [],
9770
+ options.sessionSkills ?? []
9591
9771
  ).map((selection) => Object.freeze(selection))
9592
9772
  )
9593
9773
  );
@@ -9739,11 +9919,29 @@ function buildAgentCapabilities(settings, packSkills, options = {}) {
9739
9919
  filesystemCapability,
9740
9920
  shell({ ...toolCancellation ? {} : { configureTools: withExecOpCorrelation } })
9741
9921
  ];
9922
+ const sessionSkills = sessionSkillsForMaterialization(
9923
+ packSkills,
9924
+ options.skillLibrarySkills ?? [],
9925
+ options.sessionSkills ?? []
9926
+ );
9742
9927
  caps.push(
9743
9928
  skills({
9744
- lazyFrom: lazySkillSourceWithPackSkills(packSkills, options.skillLibrarySkills ?? [])
9929
+ lazyFrom: lazySkillSourceWithPackSkills(
9930
+ [...packSkills, ...sessionSkills],
9931
+ options.skillLibrarySkills ?? []
9932
+ )
9745
9933
  })
9746
9934
  );
9935
+ if (options.workspaceSkillPaths?.length) {
9936
+ caps.push(
9937
+ workspaceSkills(options.workspaceSkillPaths, [
9938
+ ...bundledSkillDirNames(bundledSkillsDir()),
9939
+ ...(options.skillLibrarySkills ?? []).map((skill) => skill.name),
9940
+ ...packSkills.map((skill) => skill.name),
9941
+ ...sessionSkills.map((skill) => skill.name)
9942
+ ])
9943
+ );
9944
+ }
9747
9945
  if (settings.computerUseEnabled && settings.sandboxDesktopEnabled && desktopCapableBackend(settings.sandboxBackend)) {
9748
9946
  const explicitMode = options.computerToolMode;
9749
9947
  const computerCapability = computerUse({
@@ -9830,6 +10028,14 @@ async function prepareAgentTools(settings, tools, options = {}) {
9830
10028
  }, codexConnectorNamespaces };
9831
10029
  }
9832
10030
  const registry = new Map(settings.mcpServers.map((server) => [server.id, server]));
10031
+ const subjectOwnedTool = tools.find(
10032
+ (tool2) => registry.get(tool2.id)?.connectionRef?.subjectScope === "subject"
10033
+ );
10034
+ if (subjectOwnedTool && !options.credentialSubjectId) {
10035
+ throw new Error(
10036
+ `subject-owned connection for MCP server ${subjectOwnedTool.id} requires a human turn initiator`
10037
+ );
10038
+ }
9833
10039
  const aggregateToolBudget = new McpAggregateToolListBudget();
9834
10040
  const useBunNativeFetch = options.mcpFetchImpl === void 0 && !!process.versions.bun;
9835
10041
  const mcpFetchImpl = options.mcpFetchImpl ?? (useBunNativeFetch ? globalThis.fetch.bind(globalThis) : undiciFetch);
@@ -10048,7 +10254,7 @@ async function resolveConnectionForRequest(options, serverId, connectionRef, des
10048
10254
  destinationUrl,
10049
10255
  forceRefresh,
10050
10256
  ...toolName ? { toolName } : {},
10051
- ...options.subjectId ? { subjectId: options.subjectId } : {}
10257
+ ...options.credentialSubjectId ? { subjectId: options.credentialSubjectId } : {}
10052
10258
  };
10053
10259
  try {
10054
10260
  return await options.resolveCredential(request);
@@ -10280,6 +10486,7 @@ async function signFirstPartyDelegatedBearer(settings, options) {
10280
10486
  subjectId: options.subjectId ?? "worker:first-party-mcp",
10281
10487
  ...options.subjectLabel ? { subjectLabel: options.subjectLabel } : {},
10282
10488
  permissions: options.firstPartyPermissions ?? [...DEFAULT_FIRST_PARTY_MCP_PERMISSIONS],
10489
+ firstPartyMcpTools: options.firstPartyTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS],
10283
10490
  ...options.sessionId ? { sessionId: options.sessionId } : {},
10284
10491
  ...options.turnId ? { turnId: options.turnId } : {},
10285
10492
  ...options.attemptId ? { attemptId: options.attemptId } : {},
@@ -11661,6 +11868,24 @@ function buildManifest(settings, resources, environment = collectSandboxEnvironm
11661
11868
  environment
11662
11869
  });
11663
11870
  }
11871
+ function repositoryWorkspaceSkillPathsOption(resources) {
11872
+ const repositories = resources.filter(
11873
+ (resource) => resource.kind === "repository"
11874
+ );
11875
+ if (repositories.length === 0) return {};
11876
+ const paths = /* @__PURE__ */ new Map();
11877
+ const add = (path, source) => {
11878
+ if (!paths.has(path)) paths.set(path, { path, source });
11879
+ };
11880
+ add(".agents/skills", "workspace .agents/skills");
11881
+ add(".claude/skills", "workspace .claude/skills");
11882
+ for (const repository of repositories) {
11883
+ const mountPath = resourceMountPath(repository);
11884
+ add(`${mountPath}/.agents/skills`, `${mountPath}/.agents/skills`);
11885
+ add(`${mountPath}/.claude/skills`, `${mountPath}/.claude/skills`);
11886
+ }
11887
+ return { workspaceSkillPaths: [...paths.values()] };
11888
+ }
11664
11889
  function sandboxDownloadDirectory(download, mountPath) {
11665
11890
  if (download.mountPath !== mountPath) {
11666
11891
  throw new Error(
@@ -11999,7 +12224,7 @@ function gitProviderSeedEnv(provider) {
11999
12224
  return `OPENGENI_GIT_${provider.toUpperCase()}_TOKEN_SEED`;
12000
12225
  }
12001
12226
  function gitCredentialBindingHash(credentialBindingId) {
12002
- return createHash2("sha256").update(credentialBindingId, "utf8").digest("hex").slice(0, 32);
12227
+ return createHash3("sha256").update(credentialBindingId, "utf8").digest("hex").slice(0, 32);
12003
12228
  }
12004
12229
  function gitBindingSeedEnv(binding) {
12005
12230
  return `OPENGENI_GIT_BINDING_${gitCredentialBindingHash(binding.credentialBindingId).toUpperCase()}_TOKEN_SEED`;
@@ -12742,8 +12967,8 @@ function toolspaceTokenSeedCommand(options = {}) {
12742
12967
  'if [ -n "${OPENGENI_TOOLSPACE_TOKEN_SEED:-}" ]; then',
12743
12968
  ' seed_umask="$(umask)"',
12744
12969
  " umask 077",
12745
- options.tokenFile ? ` token_file=${shellQuote(options.tokenFile)}` : ' token_file="${OPENGENI_TOOLSPACE_TOKEN_FILE:-$HOME/.opengeni/toolspace-token}"',
12746
- options.legacyTokenFile ? ` legacy_token_file=${shellQuote(options.legacyTokenFile)}` : ' legacy_token_file=""',
12970
+ options.tokenFile ? ` token_file=${shellToolspacePath(options.tokenFile)}` : ' token_file="${OPENGENI_TOOLSPACE_TOKEN_FILE:-$HOME/.opengeni/toolspace-token}"',
12971
+ options.legacyTokenFile ? ` legacy_token_file=${shellToolspacePath(options.legacyTokenFile)}` : ' legacy_token_file=""',
12747
12972
  ' mkdir -p "$(dirname "$token_file")"',
12748
12973
  ` printf '%s' "$OPENGENI_TOOLSPACE_TOKEN_SEED" > "$token_file.tmp.$$"`,
12749
12974
  ' mv -f "$token_file.tmp.$$" "$token_file"',
@@ -13187,7 +13412,7 @@ function lazySkillSourceWithPackSkills(packSkills, skillLibrarySkills = []) {
13187
13412
  ]
13188
13413
  };
13189
13414
  }
13190
- function effectiveSkillSelections(librarySelections, librarySkills, packSkills) {
13415
+ function effectiveSkillSelections(librarySelections, librarySkills, packSkills, sessionSkills) {
13191
13416
  const defaultSelections = bundledSkillDirNames(bundledSkillsDir()).map((name) => ({
13192
13417
  id: `bundled:${name}`,
13193
13418
  name,
@@ -13198,14 +13423,22 @@ function effectiveSkillSelections(librarySelections, librarySkills, packSkills)
13198
13423
  }));
13199
13424
  const libraryNameKeys = new Set(librarySkills.map((skill) => skill.name.toLowerCase()));
13200
13425
  const packNameKeys = new Set(packSkills.map((skill) => skill.name.toLowerCase()));
13426
+ const effectiveSessionSkills = sessionSkillsForMaterialization(
13427
+ packSkills,
13428
+ librarySkills,
13429
+ sessionSkills
13430
+ );
13431
+ const sessionNameKeys = new Set(effectiveSessionSkills.map((skill) => skill.name.toLowerCase()));
13201
13432
  const selected = librarySelections.filter(
13202
13433
  (selection) => libraryNameKeys.has(selection.name.toLowerCase())
13203
13434
  );
13204
13435
  return [
13205
13436
  ...defaultSelections.filter(
13206
- (selection) => !libraryNameKeys.has(selection.name.toLowerCase()) && !packNameKeys.has(selection.name.toLowerCase())
13437
+ (selection) => !libraryNameKeys.has(selection.name.toLowerCase()) && !packNameKeys.has(selection.name.toLowerCase()) && !sessionNameKeys.has(selection.name.toLowerCase())
13438
+ ),
13439
+ ...selected.filter(
13440
+ (selection) => !packNameKeys.has(selection.name.toLowerCase()) && !sessionNameKeys.has(selection.name.toLowerCase())
13207
13441
  ),
13208
- ...selected.filter((selection) => !packNameKeys.has(selection.name.toLowerCase())),
13209
13442
  ...packSkills.map((skill) => ({
13210
13443
  id: `pack:${skill.name}`,
13211
13444
  name: skill.name,
@@ -13213,9 +13446,48 @@ function effectiveSkillSelections(librarySelections, librarySkills, packSkills)
13213
13446
  version: null,
13214
13447
  contentSha256: null,
13215
13448
  reason: "enabled capability pack"
13449
+ })),
13450
+ ...effectiveSessionSkills.map((skill) => ({
13451
+ id: `session:${skill.name}`,
13452
+ name: skill.name,
13453
+ source: "session",
13454
+ version: null,
13455
+ contentSha256: null,
13456
+ reason: "attached to session"
13216
13457
  }))
13217
13458
  ];
13218
13459
  }
13460
+ function sessionSkillsForMaterialization(packSkills, librarySkills, sessionSkills) {
13461
+ const configured = /* @__PURE__ */ new Map();
13462
+ for (const skill of [...librarySkills, ...packSkills]) {
13463
+ configured.set(skill.name.toLowerCase(), skill);
13464
+ }
13465
+ const bundledNames = new Set(
13466
+ bundledSkillDirNames(bundledSkillsDir()).map((name) => name.toLowerCase())
13467
+ );
13468
+ const selected = /* @__PURE__ */ new Map();
13469
+ for (const skill of sessionSkills) {
13470
+ assertSafePackSkillName(skill.name);
13471
+ const key = skill.name.toLowerCase();
13472
+ if (bundledNames.has(key)) {
13473
+ throw new Error(`Session skill "${skill.name}" conflicts with a bundled skill`);
13474
+ }
13475
+ const existing = selected.get(key) ?? configured.get(key);
13476
+ if (existing) {
13477
+ if (skillFingerprint(existing) !== skillFingerprint(skill)) {
13478
+ throw new Error(`Conflicting skill definitions for "${skill.name}"`);
13479
+ }
13480
+ continue;
13481
+ }
13482
+ selected.set(key, skill);
13483
+ }
13484
+ return [...selected.values()];
13485
+ }
13486
+ function skillFingerprint(skill) {
13487
+ return JSON.stringify(
13488
+ [...skill.files].sort((left, right) => left.path.localeCompare(right.path)).map(({ path, content }) => ({ path, content }))
13489
+ );
13490
+ }
13219
13491
  function removeSkillChildByNameKey(children, nameKey) {
13220
13492
  for (const name of Object.keys(children)) {
13221
13493
  if (name.toLowerCase() === nameKey) {
@@ -13528,7 +13800,6 @@ export {
13528
13800
  hasPersistableSandboxProviderIdentity,
13529
13801
  inspectRecordingArtifact,
13530
13802
  isCompactionSummary,
13531
- isEphemeralInternalContext,
13532
13803
  isExecSessionLostBanner,
13533
13804
  isProviderSandboxGoneDuringRoutedOperation,
13534
13805
  isProviderSandboxNotFoundError,
@@ -13590,6 +13861,7 @@ export {
13590
13861
  renderSelfhostedFault,
13591
13862
  repositoryCloneCommand,
13592
13863
  repositoryUsesSandboxClone,
13864
+ repositoryWorkspaceSkillPathsOption,
13593
13865
  requirePersistableReplacementSandboxEnvelope,
13594
13866
  resolveTurnModel,
13595
13867
  restoredSandboxSessionStateFromEntry,