@opengeni/runtime 0.13.13 → 0.14.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/index.d.ts CHANGED
@@ -371,6 +371,11 @@ declare class ComputerUseCapability extends Capability {
371
371
  private hostedComputerTool;
372
372
  }
373
373
 
374
+ type WorkspaceSkillSearchPath = Readonly<{
375
+ path: string;
376
+ source: string;
377
+ }>;
378
+
374
379
  /**
375
380
  * Read-path sanitizer for replayed conversation history (issue: orphaned
376
381
  * tool outputs brick a session).
@@ -838,7 +843,7 @@ type ToolspaceTokenWriterSession = SandboxSessionLike;
838
843
  type EffectiveSkillSelection = Readonly<{
839
844
  id: string;
840
845
  name: string;
841
- source: "bundled" | "library" | "pack";
846
+ source: "bundled" | "library" | "pack" | "session";
842
847
  version: string | null;
843
848
  contentSha256: string | null;
844
849
  reason: string;
@@ -892,6 +897,7 @@ type BuildAgentOptions = {
892
897
  sessionInstructions?: string;
893
898
  turnInstructions?: string;
894
899
  packSkills?: PackSkill[];
900
+ sessionSkills?: PackSkill[];
895
901
  skillLibrarySkills?: PackSkill[];
896
902
  skillLibrarySelections?: EffectiveSkillSelection[];
897
903
  /**
@@ -913,7 +919,7 @@ type PackSkillFile = {
913
919
  };
914
920
  type PackSkill = {
915
921
  name: string;
916
- description?: string | null;
922
+ description?: string | null | undefined;
917
923
  files: PackSkillFile[];
918
924
  };
919
925
  /**
@@ -1066,6 +1072,8 @@ declare function buildOpenGeniAgent(settings: Settings, resources: ResourceRef[]
1066
1072
  declare function withStructuredViewImageFunctionResults(tools: Tool<unknown>[]): Tool<unknown>[];
1067
1073
  declare function buildAgentCapabilities(settings: Settings, packSkills: PackSkill[], options?: {
1068
1074
  skillLibrarySkills?: PackSkill[];
1075
+ sessionSkills?: PackSkill[];
1076
+ workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
1069
1077
  structuredToolTransport?: boolean;
1070
1078
  computerToolMode?: ComputerToolMode;
1071
1079
  onComputerUseReady?: (session: SandboxSessionLike) => Promise<void>;
@@ -1087,6 +1095,7 @@ type PrepareToolsOptions = {
1087
1095
  executionGeneration?: number;
1088
1096
  subjectId?: string;
1089
1097
  subjectLabel?: string;
1098
+ credentialSubjectId?: string;
1090
1099
  firstPartyPermissions?: Permission[];
1091
1100
  resolveCredential?: (input: ResolveConnectionCredentialInput) => Promise<ResolveConnectionCredentialResult>;
1092
1101
  onAuthNeeded?: (payload: ToolAuthNeededPayload) => Promise<void> | void;
@@ -1303,6 +1312,9 @@ declare function modelResponseUsageFromResponse(response: unknown): ModelRespons
1303
1312
  declare function serializeApprovals(interruptions: unknown[]): unknown[];
1304
1313
  declare function serializeHumanInputRequests(interruptions: unknown[]): SerializedHumanInputInterruption[];
1305
1314
  declare function buildManifest(settings: Settings, resources: ResourceRef[], environment?: Record<string, string>, fileResourceDownloads?: SandboxFileDownload[]): Manifest;
1315
+ declare function repositoryWorkspaceSkillPathsOption(resources: readonly ResourceRef[]): {
1316
+ workspaceSkillPaths?: readonly WorkspaceSkillSearchPath[];
1317
+ };
1306
1318
  type SandboxLifecycleHookPhase = "beforeAgentStart";
1307
1319
  type SandboxLifecycleCommandRunner = (session: TurnSandboxCommandSession, args: TurnSandboxCommandArgs) => Promise<unknown>;
1308
1320
  type SandboxLifecycleHookContext = {
@@ -1446,4 +1458,4 @@ declare function azureOpenAIDefaultQuery(settings: Pick<Settings, "azureOpenaiAp
1446
1458
  */
1447
1459
  declare function lazySkillSourceWithPackSkills(packSkills: PackSkill[], skillLibrarySkills?: PackSkill[]): LocalDirLazySkillSource;
1448
1460
 
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 };
1461
+ 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, 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
@@ -6422,7 +6422,7 @@ import {
6422
6422
  codexSubscriptionFetch
6423
6423
  } from "@opengeni/codex";
6424
6424
  import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
6425
- import { createHash as createHash2 } from "crypto";
6425
+ import { createHash as createHash3 } from "crypto";
6426
6426
  import { dirname, isAbsolute, join, posix as posixPath, relative } from "path";
6427
6427
  import { fileURLToPath } from "url";
6428
6428
 
@@ -8480,6 +8480,184 @@ var ComputerUseCapability = class extends Capability {
8480
8480
  }
8481
8481
  };
8482
8482
 
8483
+ // src/workspace-skills.ts
8484
+ import { createHash as createHash2 } from "crypto";
8485
+ var SKILL_FILE = "SKILL.md";
8486
+ var MAX_DISCOVERED_SKILLS = 256;
8487
+ var MAX_SKILL_ENTRIES = 1024;
8488
+ var MAX_SKILL_BYTES = 32 * 1024 * 1024;
8489
+ var SAFE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
8490
+ var WorkspaceSkillsCapability = class extends Capability {
8491
+ constructor(searchPaths, reservedNames = /* @__PURE__ */ new Set()) {
8492
+ super();
8493
+ this.searchPaths = searchPaths;
8494
+ this.reservedNames = reservedNames;
8495
+ }
8496
+ type = "workspace-skills";
8497
+ discovery;
8498
+ async instructions() {
8499
+ const session = requireWorkspaceSkillSession(this._session);
8500
+ this.discovery ??= discoverWorkspaceSkills(
8501
+ session,
8502
+ this.searchPaths,
8503
+ this.reservedNames,
8504
+ this._runAs
8505
+ );
8506
+ const skills2 = await this.discovery;
8507
+ if (skills2.length === 0) return null;
8508
+ const available = skills2.map((skill) => `- ${skill.name}: ${skill.description} (file: ${skill.path})`).join("\n");
8509
+ return `## Repository skills
8510
+
8511
+ Repository skills are instructions already present in the live workspace. They do not need to be loaded or copied.
8512
+
8513
+ ### Available repository skills
8514
+ ${available}
8515
+
8516
+ ### How to use repository skills
8517
+ - If the user names a skill, or the task clearly matches a skill description, read its complete SKILL.md before acting.
8518
+ - Resolve referenced scripts, references, assets, and templates relative to that skill directory.
8519
+ - Use only the minimum relevant skills for the turn, and say briefly which ones you are using.
8520
+ - Do not assume a skill remains applicable on later turns; evaluate the current request again.`;
8521
+ }
8522
+ };
8523
+ function workspaceSkills(searchPaths, reservedNames = []) {
8524
+ return new WorkspaceSkillsCapability(
8525
+ searchPaths,
8526
+ new Set([...reservedNames].map((name) => name.toLowerCase()))
8527
+ );
8528
+ }
8529
+ async function discoverWorkspaceSkills(session, searchPaths, reservedNames = /* @__PURE__ */ new Set(), runAs) {
8530
+ if (!session.listDir || !session.readFile) {
8531
+ throw new Error("Workspace skill discovery requires sandbox listDir() and readFile() support");
8532
+ }
8533
+ const discovered = /* @__PURE__ */ new Map();
8534
+ let candidates = 0;
8535
+ for (const searchPath of searchPaths) {
8536
+ let entries;
8537
+ try {
8538
+ entries = await session.listDir({ path: searchPath.path, ...runAs ? { runAs } : {} });
8539
+ } catch {
8540
+ continue;
8541
+ }
8542
+ for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
8543
+ if (entry.type !== "dir") continue;
8544
+ candidates += 1;
8545
+ if (candidates > MAX_DISCOVERED_SKILLS) {
8546
+ throw new Error(`Repository skill discovery exceeds ${MAX_DISCOVERED_SKILLS} directories`);
8547
+ }
8548
+ const skillMarkdownPath = joinWorkspacePath(entry.path, SKILL_FILE);
8549
+ let markdown;
8550
+ try {
8551
+ const content = await session.readFile({
8552
+ path: skillMarkdownPath,
8553
+ ...runAs ? { runAs } : {}
8554
+ });
8555
+ markdown = typeof content === "string" ? content : new TextDecoder().decode(content);
8556
+ } catch {
8557
+ continue;
8558
+ }
8559
+ const frontmatter = parseSkillFrontmatter(markdown);
8560
+ const name = frontmatter.name?.trim() || entry.name;
8561
+ if (name.length > 64 || !SAFE_SKILL_NAME.test(name)) {
8562
+ throw new Error(`Repository skill has an invalid name: ${name.slice(0, 64)}`);
8563
+ }
8564
+ const description = frontmatter.description?.trim() || "No description provided.";
8565
+ if (description.length > 2048 || /[\r\n]/.test(description)) {
8566
+ throw new Error(`Repository skill "${name}" has an invalid description`);
8567
+ }
8568
+ const key = name.toLowerCase();
8569
+ if (reservedNames.has(key)) {
8570
+ throw new Error(`Workspace skill "${name}" conflicts with a configured OpenGeni skill`);
8571
+ }
8572
+ const candidate = {
8573
+ name,
8574
+ description,
8575
+ path: skillMarkdownPath,
8576
+ fingerprint: await fingerprintWorkspaceDirectory(session, entry.path, runAs),
8577
+ source: searchPath.source
8578
+ };
8579
+ const existing = discovered.get(key);
8580
+ if (!existing) {
8581
+ discovered.set(key, candidate);
8582
+ continue;
8583
+ }
8584
+ if (existing.fingerprint !== candidate.fingerprint) {
8585
+ throw new Error(
8586
+ `Workspace skill "${name}" has conflicting definitions in ${existing.source} and ${candidate.source}`
8587
+ );
8588
+ }
8589
+ }
8590
+ }
8591
+ return [...discovered.values()].sort((left, right) => left.name.localeCompare(right.name));
8592
+ }
8593
+ async function fingerprintWorkspaceDirectory(session, root, runAs) {
8594
+ const hash = createHash2("sha256");
8595
+ let entryCount = 0;
8596
+ let byteCount = 0;
8597
+ async function visit(path, relativePath) {
8598
+ const entries = await session.listDir({ path, ...runAs ? { runAs } : {} });
8599
+ for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
8600
+ entryCount += 1;
8601
+ if (entryCount > MAX_SKILL_ENTRIES) {
8602
+ throw new Error(`Workspace skill exceeds ${MAX_SKILL_ENTRIES} filesystem entries`);
8603
+ }
8604
+ const childRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
8605
+ hash.update(entry.type);
8606
+ hash.update("\0");
8607
+ hash.update(childRelativePath);
8608
+ hash.update("\0");
8609
+ if (entry.type === "dir") {
8610
+ await visit(entry.path, childRelativePath);
8611
+ continue;
8612
+ }
8613
+ if (entry.type !== "file") continue;
8614
+ const content = await session.readFile({
8615
+ path: entry.path,
8616
+ ...runAs ? { runAs } : {}
8617
+ });
8618
+ const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
8619
+ byteCount += bytes.byteLength;
8620
+ if (byteCount > MAX_SKILL_BYTES) {
8621
+ throw new Error(`Workspace skill exceeds ${MAX_SKILL_BYTES} bytes`);
8622
+ }
8623
+ hash.update(bytes);
8624
+ hash.update("\0");
8625
+ }
8626
+ }
8627
+ await visit(root, "");
8628
+ return hash.digest("hex");
8629
+ }
8630
+ function parseSkillFrontmatter(markdown) {
8631
+ const lines = markdown.split(/\r?\n/);
8632
+ if (lines[0]?.trim() !== "---") return {};
8633
+ const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
8634
+ if (end === -1) return {};
8635
+ const values = {};
8636
+ for (const line of lines.slice(1, end)) {
8637
+ const separator = line.indexOf(":");
8638
+ if (separator === -1) continue;
8639
+ const key = line.slice(0, separator).trim();
8640
+ if (key !== "name" && key !== "description") continue;
8641
+ values[key] = unquote(line.slice(separator + 1).trim());
8642
+ }
8643
+ return values;
8644
+ }
8645
+ function unquote(value) {
8646
+ if (value.length >= 2 && value[0] === value[value.length - 1] && (value[0] === '"' || value[0] === "'")) {
8647
+ return value.slice(1, -1);
8648
+ }
8649
+ return value;
8650
+ }
8651
+ function joinWorkspacePath(parent, child) {
8652
+ return `${parent.replace(/\/+$/, "")}/${child}`;
8653
+ }
8654
+ function requireWorkspaceSkillSession(session) {
8655
+ if (!session) {
8656
+ throw new Error('capability "workspace-skills" used before bind(session)');
8657
+ }
8658
+ return session;
8659
+ }
8660
+
8483
8661
  // src/usage-telemetry.ts
8484
8662
  var MAX_MODEL_USAGE_TOKEN_COUNT = 1e9;
8485
8663
  function modelUsageTokenCountOrNull(value) {
@@ -9574,6 +9752,8 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
9574
9752
  ...runAs ? { runAs } : {},
9575
9753
  capabilities: buildAgentCapabilities(settings, options.packSkills ?? [], {
9576
9754
  ...options.skillLibrarySkills?.length ? { skillLibrarySkills: options.skillLibrarySkills } : {},
9755
+ ...options.sessionSkills?.length ? { sessionSkills: options.sessionSkills } : {},
9756
+ ...repositoryWorkspaceSkillPathsOption(resources),
9577
9757
  ...options.structuredToolTransport !== void 0 ? { structuredToolTransport: options.structuredToolTransport } : {},
9578
9758
  ...options.computerToolMode !== void 0 ? { computerToolMode: options.computerToolMode } : {},
9579
9759
  ...options.onComputerUseReady ? { onComputerUseReady: options.onComputerUseReady } : {},
@@ -9587,7 +9767,8 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
9587
9767
  effectiveSkillSelections(
9588
9768
  options.skillLibrarySelections ?? [],
9589
9769
  options.skillLibrarySkills ?? [],
9590
- options.packSkills ?? []
9770
+ options.packSkills ?? [],
9771
+ options.sessionSkills ?? []
9591
9772
  ).map((selection) => Object.freeze(selection))
9592
9773
  )
9593
9774
  );
@@ -9739,11 +9920,29 @@ function buildAgentCapabilities(settings, packSkills, options = {}) {
9739
9920
  filesystemCapability,
9740
9921
  shell({ ...toolCancellation ? {} : { configureTools: withExecOpCorrelation } })
9741
9922
  ];
9923
+ const sessionSkills = sessionSkillsForMaterialization(
9924
+ packSkills,
9925
+ options.skillLibrarySkills ?? [],
9926
+ options.sessionSkills ?? []
9927
+ );
9742
9928
  caps.push(
9743
9929
  skills({
9744
- lazyFrom: lazySkillSourceWithPackSkills(packSkills, options.skillLibrarySkills ?? [])
9930
+ lazyFrom: lazySkillSourceWithPackSkills(
9931
+ [...packSkills, ...sessionSkills],
9932
+ options.skillLibrarySkills ?? []
9933
+ )
9745
9934
  })
9746
9935
  );
9936
+ if (options.workspaceSkillPaths?.length) {
9937
+ caps.push(
9938
+ workspaceSkills(options.workspaceSkillPaths, [
9939
+ ...bundledSkillDirNames(bundledSkillsDir()),
9940
+ ...(options.skillLibrarySkills ?? []).map((skill) => skill.name),
9941
+ ...packSkills.map((skill) => skill.name),
9942
+ ...sessionSkills.map((skill) => skill.name)
9943
+ ])
9944
+ );
9945
+ }
9747
9946
  if (settings.computerUseEnabled && settings.sandboxDesktopEnabled && desktopCapableBackend(settings.sandboxBackend)) {
9748
9947
  const explicitMode = options.computerToolMode;
9749
9948
  const computerCapability = computerUse({
@@ -9830,6 +10029,14 @@ async function prepareAgentTools(settings, tools, options = {}) {
9830
10029
  }, codexConnectorNamespaces };
9831
10030
  }
9832
10031
  const registry = new Map(settings.mcpServers.map((server) => [server.id, server]));
10032
+ const subjectOwnedTool = tools.find(
10033
+ (tool2) => registry.get(tool2.id)?.connectionRef?.subjectScope === "subject"
10034
+ );
10035
+ if (subjectOwnedTool && !options.credentialSubjectId) {
10036
+ throw new Error(
10037
+ `subject-owned connection for MCP server ${subjectOwnedTool.id} requires a human turn initiator`
10038
+ );
10039
+ }
9833
10040
  const aggregateToolBudget = new McpAggregateToolListBudget();
9834
10041
  const useBunNativeFetch = options.mcpFetchImpl === void 0 && !!process.versions.bun;
9835
10042
  const mcpFetchImpl = options.mcpFetchImpl ?? (useBunNativeFetch ? globalThis.fetch.bind(globalThis) : undiciFetch);
@@ -10048,7 +10255,7 @@ async function resolveConnectionForRequest(options, serverId, connectionRef, des
10048
10255
  destinationUrl,
10049
10256
  forceRefresh,
10050
10257
  ...toolName ? { toolName } : {},
10051
- ...options.subjectId ? { subjectId: options.subjectId } : {}
10258
+ ...options.credentialSubjectId ? { subjectId: options.credentialSubjectId } : {}
10052
10259
  };
10053
10260
  try {
10054
10261
  return await options.resolveCredential(request);
@@ -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`;
@@ -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) {
@@ -13590,6 +13862,7 @@ export {
13590
13862
  renderSelfhostedFault,
13591
13863
  repositoryCloneCommand,
13592
13864
  repositoryUsesSandboxClone,
13865
+ repositoryWorkspaceSkillPathsOption,
13593
13866
  requirePersistableReplacementSandboxEnvelope,
13594
13867
  resolveTurnModel,
13595
13868
  restoredSandboxSessionStateFromEntry,