@opengeni/worker-bundle 1.0.0-canary.0 → 1.0.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.
Files changed (244) hide show
  1. package/dist/activities/agent-run-admission.d.ts +3 -1
  2. package/dist/activities/agent-turn/admission.d.ts +24 -3
  3. package/dist/activities/agent-turn/agent-build.d.ts +4 -0
  4. package/dist/activities/agent-turn/claude-usage-observer.d.ts +58 -0
  5. package/dist/activities/agent-turn/code-search.d.ts +60 -0
  6. package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
  7. package/dist/activities/agent-turn/codex-plan-entitlement.d.ts +105 -0
  8. package/dist/activities/agent-turn/codex.d.ts +3 -2
  9. package/dist/activities/agent-turn/compaction-prep.d.ts +21 -5
  10. package/dist/activities/agent-turn/credential-leases.d.ts +19 -33
  11. package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
  12. package/dist/activities/agent-turn/errors.d.ts +82 -11
  13. package/dist/activities/agent-turn/failure-settlement.d.ts +6 -3
  14. package/dist/activities/agent-turn/final-reply.d.ts +18 -0
  15. package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
  16. package/dist/activities/agent-turn/finalization.d.ts +4 -2
  17. package/dist/activities/agent-turn/github-repository-bindings.d.ts +2 -0
  18. package/dist/activities/agent-turn/governance-model.d.ts +9 -2
  19. package/dist/activities/agent-turn/history-sink.d.ts +2 -0
  20. package/dist/activities/agent-turn/history.d.ts +2 -0
  21. package/dist/activities/agent-turn/input-wait-reply.d.ts +41 -0
  22. package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
  23. package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
  24. package/dist/activities/agent-turn/model-usage.d.ts +6 -0
  25. package/dist/activities/agent-turn/model-wire-dispatch.d.ts +15 -0
  26. package/dist/activities/agent-turn/optional-repositories.d.ts +59 -0
  27. package/dist/activities/agent-turn/provider-dispatch-barrier.d.ts +12 -1
  28. package/dist/activities/agent-turn/quiescence.d.ts +7 -7
  29. package/dist/activities/agent-turn/recovery-warning.d.ts +9 -0
  30. package/dist/activities/agent-turn/refresh-credentials.d.ts +6 -0
  31. package/dist/activities/agent-turn/run-credentials.d.ts +8 -3
  32. package/dist/activities/agent-turn/sandbox-establish.d.ts +2 -1
  33. package/dist/activities/agent-turn/sandbox-provision.d.ts +3 -1
  34. package/dist/activities/agent-turn/sandbox-route.d.ts +3 -20
  35. package/dist/activities/agent-turn/sandbox-runtime.d.ts +2 -2
  36. package/dist/activities/agent-turn/session-title.d.ts +34 -2
  37. package/dist/activities/agent-turn/skill-checkout.d.ts +25 -6
  38. package/dist/activities/agent-turn/skill-read.d.ts +70 -2
  39. package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
  40. package/dist/activities/agent-turn/skill-search.d.ts +3 -1
  41. package/dist/activities/agent-turn/skill-tools.d.ts +15 -2
  42. package/dist/activities/agent-turn/skill-transfer.d.ts +18 -6
  43. package/dist/activities/agent-turn/stream-attempt.d.ts +7 -3
  44. package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
  45. package/dist/activities/agent-turn/tool-environment.d.ts +56 -6
  46. package/dist/activities/agent-turn/tool-policy.d.ts +43 -0
  47. package/dist/activities/agent-turn/turn-context.d.ts +29 -0
  48. package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
  49. package/dist/activities/agent-turn/xai-capacity.d.ts +2 -1
  50. package/dist/activities/automations.d.ts +3 -1
  51. package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
  52. package/dist/activities/codemode-dispatcher.d.ts +9 -2
  53. package/dist/activities/codex-capacity.d.ts +18 -2
  54. package/dist/activities/codex-rotation.d.ts +7 -1
  55. package/dist/activities/context-compaction.d.ts +16 -2
  56. package/dist/activities/gmail-files.d.ts +32 -0
  57. package/dist/activities/goals.d.ts +8 -0
  58. package/dist/activities/knowledge-indexing.d.ts +19 -0
  59. package/dist/activities/mcp-account-routes.d.ts +3 -0
  60. package/dist/activities/mcp-credentials.d.ts +12 -13
  61. package/dist/activities/mcp-operation-authority.d.ts +0 -5
  62. package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
  63. package/dist/activities/open-suffix-resume.d.ts +13 -0
  64. package/dist/activities/parent-wake.d.ts +6 -12
  65. package/dist/activities/retained-screenshots.d.ts +7 -2
  66. package/dist/activities/rig-verification.d.ts +2 -3
  67. package/dist/activities/run-credential-renewal.d.ts +1 -0
  68. package/dist/activities/run-credentials.d.ts +15 -3
  69. package/dist/activities/sandbox-images.d.ts +1 -1
  70. package/dist/activities/sandbox-lease.d.ts +47 -9
  71. package/dist/activities/scheduled-tasks.d.ts +4 -35
  72. package/dist/activities/session-state.d.ts +70 -3
  73. package/dist/activities/types.d.ts +55 -6
  74. package/dist/activities/workspace-capture.d.ts +2 -0
  75. package/dist/activities/workspace-credential-provider.d.ts +46 -0
  76. package/dist/{activities-control-HMFGSKC5.js → activities-control-BNPTRTOE.js} +1896 -418
  77. package/dist/activities-control-BNPTRTOE.js.map +1 -0
  78. package/dist/activities-control.d.ts +182 -4
  79. package/dist/{activities-turn-AP67JADS.js → activities-turn-5LGZOSVU.js} +4476 -1327
  80. package/dist/activities-turn-5LGZOSVU.js.map +1 -0
  81. package/dist/activities.d.ts +182 -4
  82. package/dist/artifact-materializer-entry.js +5 -2
  83. package/dist/artifact-materializer-entry.js.map +1 -1
  84. package/dist/artifact-outbox-entry.js +5 -2
  85. package/dist/artifact-outbox-entry.js.map +1 -1
  86. package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
  87. package/dist/{chunk-A4XQWVZK.js → chunk-3ZTRWDMN.js} +307 -4
  88. package/dist/chunk-3ZTRWDMN.js.map +1 -0
  89. package/dist/{chunk-RAMNYSAW.js → chunk-4ER3YXOT.js} +22 -4
  90. package/dist/chunk-4ER3YXOT.js.map +1 -0
  91. package/dist/{chunk-CYITU5UH.js → chunk-LJX7Z2KP.js} +1445 -343
  92. package/dist/chunk-LJX7Z2KP.js.map +1 -0
  93. package/dist/editable-artifact-materializer-service.d.ts +2 -2
  94. package/dist/editable-artifact-outbox-service.d.ts +2 -2
  95. package/dist/host-export-pump.d.ts +3 -1
  96. package/dist/host-export.d.ts +1 -1
  97. package/dist/host-export.js +1 -1
  98. package/dist/http.d.ts +1 -1
  99. package/dist/index.d.ts +95 -3
  100. package/dist/index.js +137 -43
  101. package/dist/index.js.map +1 -1
  102. package/dist/observability-metrics.d.ts +118 -8
  103. package/dist/retained-process-diagnostics.d.ts +4 -0
  104. package/dist/retained-process-retry.d.ts +7 -0
  105. package/dist/sandbox-resume.d.ts +55 -13
  106. package/dist/sandbox-routing.d.ts +5 -3
  107. package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
  108. package/dist/session-event-fanout.d.ts +6 -0
  109. package/dist/warm-capture-holder.d.ts +3 -0
  110. package/dist/worker-service-lifecycle.d.ts +12 -0
  111. package/dist/workflow-bundle.js +273 -41
  112. package/dist/workflows/activities.d.ts +1 -1
  113. package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
  114. package/dist/workflows/scheduled-tasks.d.ts +4 -0
  115. package/dist/workflows/session.d.ts +36 -0
  116. package/dist/workflows.d.ts +1 -0
  117. package/package.json +21 -19
  118. package/src/activities/agent-run-admission.ts +17 -1
  119. package/src/activities/agent-turn/admission.ts +66 -3
  120. package/src/activities/agent-turn/agent-build.ts +84 -10
  121. package/src/activities/agent-turn/claim.ts +186 -43
  122. package/src/activities/agent-turn/claude-usage-observer.ts +221 -0
  123. package/src/activities/agent-turn/code-search.ts +275 -0
  124. package/src/activities/agent-turn/codex-capacity.ts +172 -8
  125. package/src/activities/agent-turn/codex-plan-entitlement.ts +254 -0
  126. package/src/activities/agent-turn/codex.ts +13 -5
  127. package/src/activities/agent-turn/compaction-prep.ts +170 -102
  128. package/src/activities/agent-turn/credential-leases.ts +122 -216
  129. package/src/activities/agent-turn/credential-restriction.ts +14 -0
  130. package/src/activities/agent-turn/errors.ts +647 -48
  131. package/src/activities/agent-turn/failure-settlement.ts +682 -130
  132. package/src/activities/agent-turn/final-reply.ts +46 -0
  133. package/src/activities/agent-turn/finalization-monitor.ts +120 -0
  134. package/src/activities/agent-turn/finalization.ts +146 -43
  135. package/src/activities/agent-turn/github-repository-bindings.ts +3 -1
  136. package/src/activities/agent-turn/governance-model.ts +69 -28
  137. package/src/activities/agent-turn/history-sink.ts +16 -2
  138. package/src/activities/agent-turn/history.ts +38 -11
  139. package/src/activities/agent-turn/input-wait-reply.ts +103 -0
  140. package/src/activities/agent-turn/knowledge-source-tools.ts +2 -0
  141. package/src/activities/agent-turn/media-artifacts.ts +2 -1
  142. package/src/activities/agent-turn/model-call-admission.ts +94 -0
  143. package/src/activities/agent-turn/model-usage.ts +64 -3
  144. package/src/activities/agent-turn/model-wire-dispatch.ts +27 -0
  145. package/src/activities/agent-turn/optional-repositories.ts +224 -0
  146. package/src/activities/agent-turn/provider-dispatch-barrier.ts +22 -0
  147. package/src/activities/agent-turn/quiescence.ts +10 -7
  148. package/src/activities/agent-turn/recovery-warning.ts +16 -0
  149. package/src/activities/agent-turn/refresh-credentials.ts +44 -0
  150. package/src/activities/agent-turn/run-credentials.ts +116 -55
  151. package/src/activities/agent-turn/run.ts +320 -93
  152. package/src/activities/agent-turn/sandbox-establish.ts +84 -8
  153. package/src/activities/agent-turn/sandbox-provision.ts +3 -1
  154. package/src/activities/agent-turn/sandbox-route.ts +4 -21
  155. package/src/activities/agent-turn/sandbox-runtime.ts +343 -18
  156. package/src/activities/agent-turn/session-title.ts +81 -5
  157. package/src/activities/agent-turn/skill-checkout.ts +111 -24
  158. package/src/activities/agent-turn/skill-install.ts +1 -1
  159. package/src/activities/agent-turn/skill-read.ts +374 -28
  160. package/src/activities/agent-turn/skill-remove.ts +46 -0
  161. package/src/activities/agent-turn/skill-save.ts +1 -1
  162. package/src/activities/agent-turn/skill-search.ts +10 -1
  163. package/src/activities/agent-turn/skill-selection.ts +4 -0
  164. package/src/activities/agent-turn/skill-tools.ts +112 -18
  165. package/src/activities/agent-turn/skill-transfer.ts +68 -23
  166. package/src/activities/agent-turn/stream-attempt.ts +313 -77
  167. package/src/activities/agent-turn/subscription-lease.ts +115 -0
  168. package/src/activities/agent-turn/tool-environment.ts +316 -167
  169. package/src/activities/agent-turn/tool-policy.ts +80 -1
  170. package/src/activities/agent-turn/turn-context.ts +35 -0
  171. package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
  172. package/src/activities/agent-turn/xai-capacity.ts +94 -51
  173. package/src/activities/automations.ts +76 -4
  174. package/src/activities/browser-deadline-checkpoint.ts +279 -0
  175. package/src/activities/capabilities.ts +108 -11
  176. package/src/activities/codemode-dispatcher.ts +36 -8
  177. package/src/activities/codex-capacity.ts +60 -25
  178. package/src/activities/codex-rotation.ts +39 -17
  179. package/src/activities/context-compaction.ts +75 -18
  180. package/src/activities/gmail-files.ts +88 -0
  181. package/src/activities/goals.ts +116 -121
  182. package/src/activities/google-drive-publication.ts +1 -3
  183. package/src/activities/image-generation-operation.ts +1 -1
  184. package/src/activities/knowledge-indexing.ts +269 -15
  185. package/src/activities/knowledge-source-sync.ts +10 -0
  186. package/src/activities/mcp-account-routes.ts +17 -0
  187. package/src/activities/mcp-credentials.ts +83 -194
  188. package/src/activities/mcp-operation-authority.ts +16 -41
  189. package/src/activities/model-call-fact-reconciler.ts +112 -0
  190. package/src/activities/open-suffix-resume.ts +15 -2
  191. package/src/activities/parent-wake.ts +46 -21
  192. package/src/activities/retained-screenshots.ts +82 -11
  193. package/src/activities/rig-verification.ts +38 -37
  194. package/src/activities/run-credential-renewal.ts +13 -1
  195. package/src/activities/run-credentials.ts +59 -17
  196. package/src/activities/run-input.ts +25 -16
  197. package/src/activities/sandbox-images.ts +0 -1
  198. package/src/activities/sandbox-lease.ts +798 -82
  199. package/src/activities/scheduled-tasks.ts +550 -178
  200. package/src/activities/session-state.ts +245 -6
  201. package/src/activities/site-auth-maintenance.ts +3 -0
  202. package/src/activities/types.ts +72 -5
  203. package/src/activities/workflow-wake.ts +2 -17
  204. package/src/activities/workspace-capture.ts +13 -2
  205. package/src/activities/workspace-credential-provider.ts +283 -0
  206. package/src/activities-control.ts +4 -0
  207. package/src/activities-turn.ts +5 -0
  208. package/src/activities.ts +13 -0
  209. package/src/activity-services.ts +16 -4
  210. package/src/browser-deadline-checkpoint-contract.ts +5 -0
  211. package/src/editable-artifact-hint-broker.ts +3 -0
  212. package/src/editable-artifact-materializer-service.ts +7 -3
  213. package/src/editable-artifact-outbox-service.ts +4 -4
  214. package/src/github-rest-mcp.ts +1 -2
  215. package/src/host-export-pump.ts +26 -4
  216. package/src/host-export.ts +3 -0
  217. package/src/http.ts +4 -2
  218. package/src/index.ts +99 -37
  219. package/src/observability-metrics.ts +510 -5
  220. package/src/personal-github-git-credentials.ts +2 -1
  221. package/src/pr-review-credentials.ts +1 -3
  222. package/src/retained-process-diagnostics.ts +50 -0
  223. package/src/retained-process-retry.ts +36 -0
  224. package/src/sandbox-resume.ts +388 -101
  225. package/src/sandbox-routing.ts +150 -25
  226. package/src/sandbox-snapshot-diagnostics.ts +112 -0
  227. package/src/session-event-fanout.ts +23 -0
  228. package/src/warm-capture-holder.ts +15 -0
  229. package/src/worker-service-lifecycle.ts +53 -0
  230. package/src/workflows/activities.ts +16 -1
  231. package/src/workflows/browser-deadline-checkpoint.ts +50 -0
  232. package/src/workflows/file-upload-reaper.ts +2 -0
  233. package/src/workflows/scheduled-tasks.ts +26 -13
  234. package/src/workflows/session.ts +242 -22
  235. package/src/workflows.ts +4 -0
  236. package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
  237. package/dist/activities/packs.d.ts +0 -55
  238. package/dist/activities-control-HMFGSKC5.js.map +0 -1
  239. package/dist/activities-turn-AP67JADS.js.map +0 -1
  240. package/dist/chunk-A4XQWVZK.js.map +0 -1
  241. package/dist/chunk-CYITU5UH.js.map +0 -1
  242. package/dist/chunk-RAMNYSAW.js.map +0 -1
  243. package/src/activities/agent-turn/knowledge-sources.ts +0 -86
  244. package/src/activities/packs.ts +0 -166
@@ -41,7 +41,7 @@ export function createSkillSaveAttemptToolDefinition(input: {
41
41
  codemodePath: ["opengeni", "skill_save"],
42
42
  title: "Save Skill text",
43
43
  description:
44
- "Create or edit a workspace Skill without a sandbox. Supply only changed UTF-8 text files and explicit deletions; omitted files are preserved. Use the revision and scope version returned by Skill discovery for stale-write protection. For creation choose a new UUID, set expectedRevisionId to null and expectedScopeVersion to 1. The effective Skills setting governs publication: Automatic publishes, Review first saves a pending revision in Knowledge > Needs review while the task continues, and Off prevents agent authoring. Report the actual receipt without asking an approval question. Private chats save personal Skills; shared chats save workspace Skills.",
44
+ "Create or edit a Skill for reusable procedures or context-specific and personal behavioral preferences, not retrieval-only facts. Put its applicability in the SKILL.md description so the prompt index can guide skill_read; the full body is loaded when relevant. Short always-on workspace rules use instruction_policy_save. Supply only changed UTF-8 text files and explicit deletions; omitted files are preserved. No sandbox is needed. Use the revision and scope version returned by Skill discovery for stale-write protection. For creation choose a new UUID, set expectedRevisionId to null and expectedScopeVersion to 1. The effective Skills setting governs publication: Automatic publishes, Review first saves a pending revision in Knowledge > Needs review while the task continues, and Off prevents agent authoring. Report the actual receipt without asking an approval question. Private chats save personal Skills; shared chats save workspace Skills. Preserve the intended scope; another destination is not a workaround for unavailable scope or learning restrictions.",
45
45
  inputSchema: {
46
46
  type: "object",
47
47
  properties: {
@@ -8,13 +8,15 @@ export type WorkspaceSkillSearchEntry = Readonly<{
8
8
  revisionId?: string;
9
9
  scopeVersion?: number;
10
10
  installationVersion?: number;
11
- source?: "workspace" | "builtin" | "session" | "pack";
11
+ source?: "workspace" | "builtin" | "session";
12
12
  }>;
13
13
 
14
14
  export function createSkillSearchAttemptToolDefinition(input: {
15
15
  authorize: () => Promise<void>;
16
16
  listWorkspace: () => Promise<readonly WorkspaceSkillSearchEntry[]>;
17
17
  publicSearch: PublicSkillSearchClient;
18
+ /** Ids of the readable Skills a search returned, for read telemetry only. */
19
+ onWorkspaceHits?: (ids: readonly string[]) => void;
18
20
  }): AttemptToolDefinition {
19
21
  return {
20
22
  identity: { serverId: "opengeni", toolName: "skill_search" },
@@ -59,6 +61,13 @@ export function createSkillSearchAttemptToolDefinition(input: {
59
61
  source: entry.source ?? "workspace",
60
62
  installed: !entry.source || entry.source === "workspace",
61
63
  }));
64
+ if (workspaceHits.length) {
65
+ try {
66
+ input.onWorkspaceHits?.(workspaceHits.map((entry) => entry.id));
67
+ } catch {
68
+ // Telemetry never changes a search.
69
+ }
70
+ }
62
71
  let publicResult: Awaited<ReturnType<PublicSkillSearchClient["search"]>> | null = null;
63
72
  let publicError: {
64
73
  source: "skills_sh";
@@ -14,10 +14,13 @@ export function configuredBundledSkillNames(context: BundledSkillConfiguration):
14
14
  const tools = new Set(context.firstPartyTools);
15
15
  const artifacts = () => tools.has("editable_artifact_list") && tools.has("editable_artifact_get");
16
16
  const definitions = [
17
+ { name: "opengeni-help", include: () => true },
18
+ { name: "opengeni-client", include: () => true },
17
19
  { name: "opengeni-visualize", include: () => true },
18
20
  { name: "document-parsing", include: () => true },
19
21
  { name: "opengeni-skills", include: () => true },
20
22
  { name: "opengeni-projects", include: () => true },
23
+ { name: "opengeni-schedules", include: () => tools.has("scheduled_tasks_create") },
21
24
  { name: "opengeni-documents", include: artifacts },
22
25
  { name: "opengeni-spreadsheets", include: artifacts },
23
26
  { name: "opengeni-presentations", include: artifacts },
@@ -41,6 +44,7 @@ export function loadConfiguredBundledSkills(context: BundledSkillConfiguration)
41
44
  const names = new Set(configuredBundledSkillNames(context));
42
45
  const artifacts = loadNativeToolSkillArtifacts({
43
46
  projects: names.has("opengeni-projects"),
47
+ schedules: names.has("opengeni-schedules"),
44
48
  editableArtifacts: [
45
49
  "opengeni-documents",
46
50
  "opengeni-spreadsheets",
@@ -1,8 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import type { Settings } from "@opengeni/config";
3
- import { type SkillActor, type SkillWriteReceipt } from "@opengeni/contracts";
3
+ import { type SkillActor, type SkillScope, type SkillWriteReceipt } from "@opengeni/contracts";
4
4
  import {
5
5
  assertSkillReadAttempt,
6
+ getActiveSessionFunctionToolResults,
6
7
  skillReviewResolution,
7
8
  installPortableSkill,
8
9
  replayPortableSkillInstall,
@@ -18,23 +19,35 @@ import {
18
19
  readSkill,
19
20
  resolveSkillImport,
20
21
  saveSkill,
22
+ removeSkill,
21
23
  } from "@opengeni/core";
22
24
  import {
23
25
  buildPortableSkillArtifact,
24
26
  loadSkillLibrarySkill,
27
+ skillArtifactContentSha256,
25
28
  skillLibraryRepositoryUrl,
26
29
  type SkillTextFile,
27
30
  } from "@opengeni/runtime/skill-library";
28
31
  import type { RuntimeSkillArtifact } from "@opengeni/runtime";
29
- import type { SandboxChannelAService } from "@opengeni/runtime/sandbox";
30
- import { createSkillReadAttemptToolDefinition, type SkillReadContent } from "./skill-read";
32
+ import {
33
+ createSkillReadAttemptToolDefinition,
34
+ SKILL_READ_TOOL_NAME,
35
+ type SelectedSkillReadContent,
36
+ type SkillReadContent,
37
+ type SkillReadObservation,
38
+ type SkillReadOrigin,
39
+ unavailableSkillError,
40
+ } from "./skill-read";
31
41
  import { createSkillSearchAttemptToolDefinition } from "./skill-search";
32
42
  import { createSkillSaveAttemptToolDefinition, type SkillSaveRequest } from "./skill-save";
33
43
  import { createSkillInstallAttemptToolDefinition } from "./skill-install";
44
+ import { createSkillRemoveAttemptToolDefinition } from "./skill-remove";
34
45
  import {
35
46
  createSkillCheckoutAttemptToolDefinition,
36
47
  createSkillPublishAttemptToolDefinition,
48
+ type SkillCheckoutObservation,
37
49
  } from "./skill-checkout";
50
+ import type { SkillFileSystem } from "./skill-transfer";
38
51
 
39
52
  export function createWorkspaceSkillTools(input: {
40
53
  db: Database;
@@ -44,9 +57,18 @@ export function createWorkspaceSkillTools(input: {
44
57
  subjectId?: string;
45
58
  actor: Extract<SkillActor, { kind: "agent" }>;
46
59
  selected: readonly { id: string; artifact: RuntimeSkillArtifact }[];
47
- filesystem: () => Promise<
48
- Pick<SandboxChannelAService, "fsList" | "fsRead" | "fsWrite" | "fsMkdir">
49
- >;
60
+ filesystem: () => Promise<SkillFileSystem>;
61
+ /** Content-free skill_checkout timing; it never changes a result. */
62
+ observeSkillCheckout?: (observation: SkillCheckoutObservation) => void;
63
+ /** The resolved model's bound, which `settings` does not carry. */
64
+ modelToolOutputTruncationTokens: () => number;
65
+ onSkillReadHistoryLookupFailed?: (error: unknown) => void;
66
+ /** Content-free skill_read telemetry; it never changes a result. */
67
+ skillReadTelemetry?: {
68
+ /** Ids in the Skill index the model sees this turn; null until known. */
69
+ indexedSkillIds: () => ReadonlySet<string> | null;
70
+ observe: (observation: SkillReadObservation) => void;
71
+ };
50
72
  }) {
51
73
  const context = {
52
74
  accountId: input.accountId,
@@ -55,15 +77,17 @@ export function createWorkspaceSkillTools(input: {
55
77
  };
56
78
  const authorize = () => assertSkillReadAttempt(input.db, { ...context, actor: input.actor });
57
79
  const selected = new Map(input.selected.map((entry) => [entry.id, entry.artifact]));
80
+ // Readable Skills that skill_search returned in this attempt.
81
+ const searchedSkillIds = new Set<string>();
58
82
  const list = async () =>
59
83
  (await listSkillDescriptors(input.db, context)).filter(
60
84
  (entry) => entry.activationMode === "workspace_managed",
61
85
  );
62
86
  // Both text reads and inventory resolve through this same authorized source.
63
87
  // Selected artifacts have no ledger revision identity; never synthesize one.
64
- const load = async (identifier: string): Promise<readonly SkillTextFile[] | SkillReadContent> => {
88
+ const load = async (identifier: string): Promise<SkillReadContent | SelectedSkillReadContent> => {
65
89
  const exact = selected.get(identifier);
66
- if (exact) return exact.files;
90
+ if (exact) return selectedSkillContent(identifier, exact);
67
91
  const descriptors = await list();
68
92
  const exactWorkspace = descriptors.find((entry) => entry.id === identifier);
69
93
  const matches = exactWorkspace
@@ -76,9 +100,15 @@ export function createWorkspaceSkillTools(input: {
76
100
  throw new Error(
77
101
  "Multiple Skills match that name. Use the Skill id from the index or search.",
78
102
  );
79
- if (!matches.length && selectedMatches.length === 1) return selectedMatches[0]![1].files;
103
+ if (!matches.length && selectedMatches.length === 1)
104
+ return selectedSkillContent(selectedMatches[0]![0], selectedMatches[0]![1]);
80
105
  const match = matches[0];
81
- if (!match) throw new Error("Skill is not available in this session.");
106
+ // skill_checkout resolves through this reader too, so both return the list.
107
+ if (!match)
108
+ throw unavailableSkillError(identifier, [
109
+ ...descriptors.map((entry) => ({ id: entry.id, name: entry.title })),
110
+ ...[...selected].map(([id, artifact]) => ({ id, name: artifact.name })),
111
+ ]);
82
112
  const record = await readSkill(input.db, context, match.id);
83
113
  if (
84
114
  !record ||
@@ -95,6 +125,7 @@ export function createWorkspaceSkillTools(input: {
95
125
  ? { installationVersion: match.installationVersion }
96
126
  : {}),
97
127
  files: record.files,
128
+ origin: { id: record.id, source: registrySkillSource(record.scope) },
98
129
  };
99
130
  };
100
131
  const withReviewState = async (receipt: SkillWriteReceipt) => {
@@ -122,7 +153,39 @@ export function createWorkspaceSkillTools(input: {
122
153
  );
123
154
  };
124
155
  return [
125
- createSkillReadAttemptToolDefinition({ authorize, load }),
156
+ createSkillRemoveAttemptToolDefinition({
157
+ authorize,
158
+ remove: async (request) =>
159
+ withReviewState(
160
+ await removeSkill(input.db, { ...context, ...request, actor: input.actor }),
161
+ ),
162
+ }),
163
+ createSkillReadAttemptToolDefinition({
164
+ authorize,
165
+ load,
166
+ activeHistory: {
167
+ readResults: async () =>
168
+ (
169
+ await getActiveSessionFunctionToolResults(input.db, {
170
+ workspaceId: input.workspaceId,
171
+ sessionId: input.actor.sessionId,
172
+ toolName: SKILL_READ_TOOL_NAME,
173
+ })
174
+ ).map((row) => row.item),
175
+ toolOutputTruncationTokens: input.modelToolOutputTruncationTokens,
176
+ ...(input.onSkillReadHistoryLookupFailed
177
+ ? { onLookupFailed: input.onSkillReadHistoryLookupFailed }
178
+ : {}),
179
+ },
180
+ ...(input.skillReadTelemetry
181
+ ? {
182
+ telemetry: {
183
+ ...input.skillReadTelemetry,
184
+ searched: (id: string) => searchedSkillIds.has(id),
185
+ },
186
+ }
187
+ : {}),
188
+ }),
126
189
  createSkillSearchAttemptToolDefinition({
127
190
  authorize,
128
191
  listWorkspace: async () => [
@@ -140,14 +203,13 @@ export function createWorkspaceSkillTools(input: {
140
203
  id: entry.id,
141
204
  name: entry.artifact.name,
142
205
  description: entry.artifact.description || entry.artifact.name,
143
- source: entry.id.startsWith("builtin:")
144
- ? ("builtin" as const)
145
- : entry.id.startsWith("session:")
146
- ? ("session" as const)
147
- : ("pack" as const),
206
+ source: entry.id.startsWith("builtin:") ? ("builtin" as const) : ("session" as const),
148
207
  })),
149
208
  ],
150
209
  publicSearch: createPublicSkillSearchClient(input.settings),
210
+ onWorkspaceHits: (ids) => {
211
+ for (const id of ids) searchedSkillIds.add(id);
212
+ },
151
213
  }),
152
214
  createSkillSaveAttemptToolDefinition({
153
215
  authorize,
@@ -241,10 +303,11 @@ export function createWorkspaceSkillTools(input: {
241
303
  createSkillCheckoutAttemptToolDefinition({
242
304
  authorize,
243
305
  filesystem: input.filesystem,
306
+ ...(input.observeSkillCheckout ? { observe: input.observeSkillCheckout } : {}),
244
307
  load: async (skill) => {
245
308
  const content = await load(skill);
246
- if (!("files" in content))
247
- return { skillId: skill, revisionId: null, scopeVersion: null, files: content };
309
+ if (!("skillId" in content))
310
+ return { skillId: skill, revisionId: null, scopeVersion: null, files: content.files };
248
311
  return content;
249
312
  },
250
313
  }),
@@ -252,6 +315,37 @@ export function createWorkspaceSkillTools(input: {
252
315
  ];
253
316
  }
254
317
 
318
+ function registrySkillSource(scope: SkillScope): SkillReadOrigin["source"] {
319
+ return scope === "user" ? "personal" : scope;
320
+ }
321
+
322
+ // Artifacts are immutable, so each digest is computed once per loaded artifact.
323
+ const selectedArtifactDigests = new WeakMap<RuntimeSkillArtifact, string | null>();
324
+
325
+ function selectedSkillContent(
326
+ id: string,
327
+ artifact: RuntimeSkillArtifact,
328
+ ): SelectedSkillReadContent {
329
+ let digest = selectedArtifactDigests.get(artifact);
330
+ if (digest === undefined) {
331
+ try {
332
+ digest = skillArtifactContentSha256(artifact.files);
333
+ } catch {
334
+ // Telemetry identity only; an unhashable artifact still reads.
335
+ digest = null;
336
+ }
337
+ selectedArtifactDigests.set(artifact, digest);
338
+ }
339
+ return {
340
+ files: artifact.files,
341
+ origin: {
342
+ id,
343
+ source: id.startsWith("builtin:") ? "builtin" : "session",
344
+ ...(digest ? { contentSha256: digest } : {}),
345
+ },
346
+ };
347
+ }
348
+
255
349
  function fileMetadata(files: readonly SkillTextFile[]) {
256
350
  return files.map((file) => ({
257
351
  ...file,
@@ -6,10 +6,12 @@ import {
6
6
  PORTABLE_SKILL_MAX_FILES,
7
7
  PORTABLE_SKILL_MAX_FILE_BYTES,
8
8
  PORTABLE_SKILL_MAX_TOTAL_BYTES,
9
+ SKILL_READ_MAX_PATHS,
10
+ SkillFileError,
9
11
  type SkillTextFile,
10
12
  } from "@opengeni/runtime/skill-library";
11
13
 
12
- type SkillFileSystem = Pick<SandboxChannelAService, "fsList" | "fsRead" | "fsWrite" | "fsMkdir">;
14
+ export type SkillFileSystem = Pick<SandboxChannelAService, "fsList" | "fsRead" | "fsWriteFiles">;
13
15
  const maxTraversalEntries = 1024;
14
16
 
15
17
  /** Reuse the host's cancellation and workspace-mutation authority for each filesystem operation. */
@@ -31,36 +33,76 @@ export function guardSkillFilesystem(
31
33
  return {
32
34
  fsList: (request) => read(() => fs.fsList(request)),
33
35
  fsRead: (request) => read(() => fs.fsRead(request)),
34
- fsWrite: (request) => write(() => fs.fsWrite(request)),
35
- fsMkdir: (request) => write(() => fs.fsMkdir(request)),
36
+ fsWriteFiles: (request) => write(() => fs.fsWriteFiles(request)),
36
37
  };
37
38
  }
38
39
 
39
- /** Caller supplies an authorized live filesystem and a fresh workspace-relative target. */
40
+ export type SkillCheckoutResult = {
41
+ directory: string;
42
+ fileCount: number;
43
+ written: number;
44
+ unchanged: number;
45
+ /** This call created the directory, so it holds nothing but these files. */
46
+ createdDirectory: boolean;
47
+ };
48
+
49
+ /**
50
+ * Caller supplies an authorized live filesystem and a workspace-relative
51
+ * target. All missing files are created in one filesystem batch (normally a
52
+ * single sandbox command). Nothing is overwritten: files already holding the
53
+ * same bytes are kept, and any other existing entry fails before writing.
54
+ * `paths` selects exactly those Skill files, for example one script to run.
55
+ */
40
56
  export async function checkoutSkillDirectory(
41
- fs: SkillFileSystem,
57
+ fs: Pick<SkillFileSystem, "fsWriteFiles">,
42
58
  directory: string,
43
59
  files: readonly SkillTextFile[],
44
- ): Promise<{ directory: string; fileCount: number }> {
60
+ options: { paths?: readonly string[] } = {},
61
+ ): Promise<SkillCheckoutResult> {
45
62
  assertSkillRelativePath(directory);
46
63
  const artifact = buildPortableSkillArtifact(files);
47
- const parent = posix.dirname(directory);
48
- if (parent !== ".") await fs.fsMkdir({ path: parent, recursive: true });
49
- // Never overwrite an earlier checkout (which may now contain the user's edits).
50
- await fs.fsMkdir({ path: directory, recursive: false });
51
- for (const file of artifact.files) {
52
- const result = await fs.fsWrite({
53
- path: `${directory}/${file.path}`,
54
- content: file.content,
55
- encoding: "utf8",
56
- overwrite: false,
57
- createParents: true,
58
- });
59
- if (result.sizeBytes !== new TextEncoder().encode(file.content).byteLength) {
60
- throw new Error(`Skill checkout wrote an unexpected byte count: ${file.path}`);
61
- }
64
+ const selected =
65
+ options.paths === undefined
66
+ ? artifact.files
67
+ : selectSkillCheckoutFiles(artifact.files, options.paths);
68
+ const result = await fs.fsWriteFiles({
69
+ directory,
70
+ files: selected.map((file) => ({ path: file.path, content: file.content, encoding: "utf8" })),
71
+ });
72
+ if (result.written.length + result.unchanged.length !== selected.length) {
73
+ throw new Error("Skill checkout returned an incomplete result.");
74
+ }
75
+ return {
76
+ directory,
77
+ fileCount: selected.length,
78
+ written: result.written.length,
79
+ unchanged: result.unchanged.length,
80
+ createdDirectory: result.createdDirectory,
81
+ };
82
+ }
83
+
84
+ function selectSkillCheckoutFiles(
85
+ files: readonly SkillTextFile[],
86
+ paths: readonly string[],
87
+ ): SkillTextFile[] {
88
+ if (paths.length === 0 || paths.length > SKILL_READ_MAX_PATHS) {
89
+ throw new SkillFileError(
90
+ "invalid_request",
91
+ `Request between 1 and ${SKILL_READ_MAX_PATHS} paths, or omit paths for the whole Skill.`,
92
+ );
62
93
  }
63
- return { directory, fileCount: artifact.files.length };
94
+ const byPath = new Map(files.map((file) => [file.path, file]));
95
+ const seen = new Set<string>();
96
+ return paths.map((path) => {
97
+ assertSkillRelativePath(path);
98
+ if (seen.has(path)) {
99
+ throw new SkillFileError("invalid_request", `Duplicate requested Skill path: ${path}`);
100
+ }
101
+ seen.add(path);
102
+ const file = byPath.get(path);
103
+ if (!file) throw new SkillFileError("missing_file", `Skill file not found: ${path}`);
104
+ return file;
105
+ });
64
106
  }
65
107
 
66
108
  /**
@@ -68,7 +110,10 @@ export async function checkoutSkillDirectory(
68
110
  * arguments. The caller owns workspace confinement and the final governed save.
69
111
  * This operation does not execute scripts or activate the resulting artifact.
70
112
  */
71
- export async function readSkillDirectory(fs: SkillFileSystem, directory: string) {
113
+ export async function readSkillDirectory(
114
+ fs: Pick<SkillFileSystem, "fsList" | "fsRead">,
115
+ directory: string,
116
+ ) {
72
117
  assertSkillRelativePath(directory);
73
118
  const pending = [directory];
74
119
  const seen = new Set<string>(pending);