oh-my-knowledge 1.0.0-beta.12 → 1.0.0-beta.13

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 (184) hide show
  1. package/README.md +15 -3
  2. package/README.zh.md +15 -3
  3. package/dist/assets/agent-skills/omk/references/commands.md +20 -0
  4. package/dist/cli/commands/eval/task.d.ts +13 -0
  5. package/dist/cli/commands/eval/task.js +42 -0
  6. package/dist/eval-workflows/hosts/local-task/acceptance.d.ts +13 -0
  7. package/dist/eval-workflows/hosts/local-task/acceptance.js +101 -0
  8. package/dist/eval-workflows/hosts/local-task/application.d.ts +99 -0
  9. package/dist/eval-workflows/hosts/local-task/application.js +177 -0
  10. package/dist/eval-workflows/hosts/local-task/diagnostics.d.ts +27 -0
  11. package/dist/eval-workflows/hosts/local-task/diagnostics.js +30 -0
  12. package/dist/eval-workflows/hosts/local-task/executor.d.ts +19 -0
  13. package/dist/eval-workflows/hosts/local-task/executor.js +135 -0
  14. package/dist/eval-workflows/hosts/local-task/files.d.ts +15 -0
  15. package/dist/eval-workflows/hosts/local-task/files.js +88 -0
  16. package/dist/eval-workflows/hosts/local-task/workspace.d.ts +6 -0
  17. package/dist/eval-workflows/hosts/local-task/workspace.js +32 -0
  18. package/dist/eval-workflows/inputs/contracts/local-task-evidence.d.ts +46 -0
  19. package/dist/eval-workflows/inputs/contracts/local-task-evidence.js +26 -0
  20. package/dist/eval-workflows/inputs/contracts/local-task.d.ts +50 -0
  21. package/dist/eval-workflows/inputs/contracts/local-task.js +33 -0
  22. package/dist/eval-workflows/projections/local-task.d.ts +23 -0
  23. package/dist/eval-workflows/projections/local-task.js +25 -0
  24. package/dist/executors/openai/codex/protocol.js +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +1 -0
  27. package/dist/knowledge/contracts.d.ts +4 -4
  28. package/dist/knowledge/store.d.ts +3 -3
  29. package/dist/observability/contracts/experience-evidence-schema.d.ts +29 -29
  30. package/dist/observability/knowledge-extraction/application.d.ts +10 -10
  31. package/dist/observability/knowledge-extraction/proposals.d.ts +2 -2
  32. package/dist/observability/knowledge-extraction/runs.d.ts +2 -2
  33. package/dist/studio/application/measure/core-run-format.js +2 -1
  34. package/dist/studio/application/measure/core-run-projection.js +12 -0
  35. package/dist/studio/http/next-server.js +1 -1
  36. package/dist/studio/http/pages/measure-page.d.ts +1 -0
  37. package/dist/studio/http/pages/measure-page.js +2 -2
  38. package/dist/studio/view-models/measure/core-runs.d.ts +32 -0
  39. package/dist/studio/web/.next/BUILD_ID +1 -1
  40. package/dist/studio/web/.next/app-path-routes-manifest.json +3 -3
  41. package/dist/studio/web/.next/build-manifest.json +4 -4
  42. package/dist/studio/web/.next/prerender-manifest.json +3 -3
  43. package/dist/studio/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  44. package/dist/studio/web/.next/server/app/_global-error.html +1 -1
  45. package/dist/studio/web/.next/server/app/_global-error.rsc +4 -4
  46. package/dist/studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +4 -4
  47. package/dist/studio/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +4 -4
  48. package/dist/studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  49. package/dist/studio/web/.next/server/app/_not-found/page.js +1 -1
  50. package/dist/studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  51. package/dist/studio/web/.next/server/app/agents/page.js +1 -1
  52. package/dist/studio/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  53. package/dist/studio/web/.next/server/app/knowledge/candidates/page.js +1 -1
  54. package/dist/studio/web/.next/server/app/knowledge/candidates/page_client-reference-manifest.js +1 -1
  55. package/dist/studio/web/.next/server/app/knowledge/managed/[managedId]/page.js +1 -1
  56. package/dist/studio/web/.next/server/app/knowledge/managed/[managedId]/page.js.nft.json +1 -1
  57. package/dist/studio/web/.next/server/app/knowledge/managed/[managedId]/page_client-reference-manifest.js +1 -1
  58. package/dist/studio/web/.next/server/app/knowledge/managed/page.js +1 -1
  59. package/dist/studio/web/.next/server/app/knowledge/managed/page.js.nft.json +1 -1
  60. package/dist/studio/web/.next/server/app/knowledge/managed/page_client-reference-manifest.js +1 -1
  61. package/dist/studio/web/.next/server/app/knowledge/page.js +1 -1
  62. package/dist/studio/web/.next/server/app/knowledge/page.js.nft.json +1 -1
  63. package/dist/studio/web/.next/server/app/knowledge/page_client-reference-manifest.js +1 -1
  64. package/dist/studio/web/.next/server/app/knowledge/skills/[skillName]/page.js +1 -1
  65. package/dist/studio/web/.next/server/app/knowledge/skills/[skillName]/page.js.nft.json +1 -1
  66. package/dist/studio/web/.next/server/app/knowledge/skills/[skillName]/page_client-reference-manifest.js +1 -1
  67. package/dist/studio/web/.next/server/app/measure/[runId]/page.js +1 -1
  68. package/dist/studio/web/.next/server/app/measure/[runId]/page.js.nft.json +1 -1
  69. package/dist/studio/web/.next/server/app/measure/[runId]/page_client-reference-manifest.js +1 -1
  70. package/dist/studio/web/.next/server/app/measure/page.js +1 -1
  71. package/dist/studio/web/.next/server/app/measure/page.js.nft.json +1 -1
  72. package/dist/studio/web/.next/server/app/measure/page_client-reference-manifest.js +1 -1
  73. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/page.js +1 -1
  74. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/page.js.nft.json +1 -1
  75. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/page_client-reference-manifest.js +1 -1
  76. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/tasks/[turnId]/page.js +1 -1
  77. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/tasks/[turnId]/page.js.nft.json +1 -1
  78. package/dist/studio/web/.next/server/app/observe/conversations/[threadId]/tasks/[turnId]/page_client-reference-manifest.js +1 -1
  79. package/dist/studio/web/.next/server/app/observe/health/[analysisId]/page.js +1 -1
  80. package/dist/studio/web/.next/server/app/observe/health/[analysisId]/page.js.nft.json +1 -1
  81. package/dist/studio/web/.next/server/app/observe/health/[analysisId]/page_client-reference-manifest.js +1 -1
  82. package/dist/studio/web/.next/server/app/observe/health/page.js +1 -1
  83. package/dist/studio/web/.next/server/app/observe/health/page.js.nft.json +1 -1
  84. package/dist/studio/web/.next/server/app/observe/health/page_client-reference-manifest.js +1 -1
  85. package/dist/studio/web/.next/server/app/observe/health-diff/page.js +1 -1
  86. package/dist/studio/web/.next/server/app/observe/health-diff/page.js.nft.json +1 -1
  87. package/dist/studio/web/.next/server/app/observe/health-diff/page_client-reference-manifest.js +1 -1
  88. package/dist/studio/web/.next/server/app/observe/inbox/page.js +2 -2
  89. package/dist/studio/web/.next/server/app/observe/inbox/page.js.nft.json +1 -1
  90. package/dist/studio/web/.next/server/app/observe/inbox/page_client-reference-manifest.js +1 -1
  91. package/dist/studio/web/.next/server/app/observe/page.js +1 -1
  92. package/dist/studio/web/.next/server/app/observe/page.js.nft.json +1 -1
  93. package/dist/studio/web/.next/server/app/observe/page_client-reference-manifest.js +1 -1
  94. package/dist/studio/web/.next/server/app/observe/skill-trend/[skillName]/page.js +1 -1
  95. package/dist/studio/web/.next/server/app/observe/skill-trend/[skillName]/page.js.nft.json +1 -1
  96. package/dist/studio/web/.next/server/app/observe/skill-trend/[skillName]/page_client-reference-manifest.js +1 -1
  97. package/dist/studio/web/.next/server/app-paths-manifest.json +3 -3
  98. package/dist/studio/web/.next/server/chunks/3.js +1 -2
  99. package/dist/studio/web/.next/server/chunks/335.js +1 -1
  100. package/dist/studio/web/.next/server/chunks/374.js +1 -1
  101. package/dist/studio/web/.next/server/chunks/475.js +1 -1
  102. package/dist/studio/web/.next/server/chunks/499.js +1 -1
  103. package/dist/studio/web/.next/server/chunks/5.js +1 -0
  104. package/dist/studio/web/.next/server/chunks/740.js +3 -0
  105. package/dist/studio/web/.next/server/chunks/789.js +6 -0
  106. package/dist/studio/web/.next/server/chunks/827.js +4 -4
  107. package/dist/studio/web/.next/server/chunks/84.js +1 -1
  108. package/dist/studio/web/.next/server/chunks/955.js +1 -1
  109. package/dist/studio/web/.next/server/chunks/996.js +1 -0
  110. package/dist/studio/web/.next/server/middleware-build-manifest.js +1 -1
  111. package/dist/studio/web/.next/server/pages/500.html +1 -1
  112. package/dist/studio/web/.next/server/server-reference-manifest.json +1 -1
  113. package/dist/studio/web/.next/server/webpack-runtime.js +1 -1
  114. package/dist/studio/web/.next/static/chunks/{1858-c24dcd678cdcae50.js → 1858-3ad7971aef7540de.js} +1 -1
  115. package/dist/studio/web/.next/static/chunks/2038-b941bab2ee1ef91a.js +1 -0
  116. package/dist/studio/web/.next/static/chunks/{2666-2770e8e4b4caab0e.js → 2666-022e0893a8ce80b1.js} +1 -1
  117. package/dist/studio/web/.next/static/chunks/{285-6d4538bae9d2657f.js → 285-ee2bde496eae900b.js} +1 -1
  118. package/dist/studio/web/.next/static/chunks/{2953-a2797c8e2c97e052.js → 2953-32389c228338c03f.js} +1 -1
  119. package/dist/studio/web/.next/static/chunks/3958-b95d9b60fc7f9eaf.js +1 -0
  120. package/dist/studio/web/.next/static/chunks/{4684-f60cec1af16cc02a.js → 4684-62296d31718b47b2.js} +1 -1
  121. package/dist/studio/web/.next/static/chunks/5067-75d71f6808309f44.js +6 -0
  122. package/dist/studio/web/.next/static/chunks/5669-9f0ec3bc92ab3392.js +3 -0
  123. package/dist/studio/web/.next/static/chunks/{5834-4a1f3c2c259a1918.js → 5834-ceadd3ef88dd5027.js} +1 -1
  124. package/dist/studio/web/.next/static/chunks/{6651-3212253f7d2d141f.js → 6651-392fd48cf473d253.js} +2 -2
  125. package/dist/studio/web/.next/static/chunks/{7576-c700fccfc712c394.js → 7576-0651db5aa8473f62.js} +2 -2
  126. package/dist/studio/web/.next/static/chunks/8284-399476b82eb468d0.js +1 -0
  127. package/dist/studio/web/.next/static/chunks/{8791-628c2e7b0dab299a.js → 8791-cc9640eb97b0ac98.js} +1 -1
  128. package/dist/studio/web/.next/static/chunks/9688-8fc2ea8f15ab0642.js +1 -0
  129. package/dist/studio/web/.next/static/chunks/app/agents/page-5566ed76365fc033.js +1 -0
  130. package/dist/studio/web/.next/static/chunks/app/{error-66775c241a4b5db1.js → error-da3a9e3657f1dc15.js} +1 -1
  131. package/dist/studio/web/.next/static/chunks/app/knowledge/candidates/{page-4202293fa248f263.js → page-8f6377569b01b64e.js} +1 -1
  132. package/dist/studio/web/.next/static/chunks/app/knowledge/managed/[managedId]/page-e8aa43310b5ab528.js +1 -0
  133. package/dist/studio/web/.next/static/chunks/app/knowledge/managed/page-cbae9028d8b57dcf.js +1 -0
  134. package/dist/studio/web/.next/static/chunks/app/knowledge/page-92a6b1ddc3e44d8b.js +1 -0
  135. package/dist/studio/web/.next/static/chunks/app/knowledge/skills/[skillName]/page-082ada30d2554c7e.js +1 -0
  136. package/dist/studio/web/.next/static/chunks/app/layout-872f1dfcd7ede526.js +1 -0
  137. package/dist/studio/web/.next/static/chunks/app/{loading-cc65be1028090c98.js → loading-459503db9bf76ee0.js} +1 -1
  138. package/dist/studio/web/.next/static/chunks/app/measure/[runId]/page-1b6e584362fa1fc7.js +1 -0
  139. package/dist/studio/web/.next/static/chunks/app/measure/page-94c52f9a44a8b88e.js +1 -0
  140. package/dist/studio/web/.next/static/chunks/app/{not-found-bcac3c26cbb1b3ed.js → not-found-5b86ee2b9fd19a95.js} +1 -1
  141. package/dist/studio/web/.next/static/chunks/app/observe/conversations/[threadId]/page-327796657a0b2692.js +1 -0
  142. package/dist/studio/web/.next/static/chunks/app/observe/conversations/[threadId]/tasks/[turnId]/page-1c806e81831e69b9.js +1 -0
  143. package/dist/studio/web/.next/static/chunks/app/observe/health/[analysisId]/page-41dd612e29247f6f.js +1 -0
  144. package/dist/studio/web/.next/static/chunks/app/observe/health/page-66161c7025058683.js +1 -0
  145. package/dist/studio/web/.next/static/chunks/app/observe/health-diff/page-373e7ca6f18a4594.js +1 -0
  146. package/dist/studio/web/.next/static/chunks/app/observe/inbox/{page-5003e5561490047b.js → page-923860677b6af0ad.js} +1 -1
  147. package/dist/studio/web/.next/static/chunks/app/observe/page-ff04bfbae9e9c409.js +1 -0
  148. package/dist/studio/web/.next/static/chunks/app/observe/skill-trend/[skillName]/page-4711e930a7c6a790.js +1 -0
  149. package/dist/studio/web/.next/static/chunks/{main-c9db6abe2bb89249.js → main-be4276342bf776ea.js} +1 -1
  150. package/dist/studio/web/.next/static/chunks/webpack-ac24233801701b11.js +1 -0
  151. package/dist/studio/web/.next/static/css/bc117f6d956d35b6.css +1 -0
  152. package/dist/studio/web/.next/trace +47 -42
  153. package/dist/studio/web/.next/trace-build +1 -1
  154. package/package.json +5 -3
  155. package/dist/studio/web/.next/server/chunks/209.js +0 -1
  156. package/dist/studio/web/.next/server/chunks/384.js +0 -1
  157. package/dist/studio/web/.next/server/chunks/388.js +0 -1
  158. package/dist/studio/web/.next/server/chunks/42.js +0 -1
  159. package/dist/studio/web/.next/server/chunks/767.js +0 -6
  160. package/dist/studio/web/.next/static/chunks/2038-fe4b8b7ee5f7cd19.js +0 -1
  161. package/dist/studio/web/.next/static/chunks/6250-1c80598e5a04a823.js +0 -2
  162. package/dist/studio/web/.next/static/chunks/8038-9d97f8fe79c7f7d4.js +0 -6
  163. package/dist/studio/web/.next/static/chunks/8284-dca5d2249647425f.js +0 -1
  164. package/dist/studio/web/.next/static/chunks/9386-d62507b1afffde3c.js +0 -1
  165. package/dist/studio/web/.next/static/chunks/9688-568cb3f8978b37e8.js +0 -1
  166. package/dist/studio/web/.next/static/chunks/app/agents/page-3cd33e679bd540fb.js +0 -1
  167. package/dist/studio/web/.next/static/chunks/app/knowledge/managed/[managedId]/page-9f18fce00bf621dc.js +0 -1
  168. package/dist/studio/web/.next/static/chunks/app/knowledge/managed/page-4e9b40acd4e5130b.js +0 -1
  169. package/dist/studio/web/.next/static/chunks/app/knowledge/page-673896d1f93ec57d.js +0 -1
  170. package/dist/studio/web/.next/static/chunks/app/knowledge/skills/[skillName]/page-28c63ecbe6a8d515.js +0 -1
  171. package/dist/studio/web/.next/static/chunks/app/layout-26d16d7c66539fc1.js +0 -1
  172. package/dist/studio/web/.next/static/chunks/app/measure/[runId]/page-f6b816f8eb408bb9.js +0 -1
  173. package/dist/studio/web/.next/static/chunks/app/measure/page-8d42458a7c786a5a.js +0 -1
  174. package/dist/studio/web/.next/static/chunks/app/observe/conversations/[threadId]/page-ebc25fa3c7ad85c3.js +0 -1
  175. package/dist/studio/web/.next/static/chunks/app/observe/conversations/[threadId]/tasks/[turnId]/page-2602b9d82e415bfc.js +0 -1
  176. package/dist/studio/web/.next/static/chunks/app/observe/health/[analysisId]/page-b32cc1278399d1a0.js +0 -1
  177. package/dist/studio/web/.next/static/chunks/app/observe/health/page-3d8f7c136a55c349.js +0 -1
  178. package/dist/studio/web/.next/static/chunks/app/observe/health-diff/page-3ca3d158cd147ef5.js +0 -1
  179. package/dist/studio/web/.next/static/chunks/app/observe/page-4a9a6d1984a94eff.js +0 -1
  180. package/dist/studio/web/.next/static/chunks/app/observe/skill-trend/[skillName]/page-1a9d9d1ac593f16d.js +0 -1
  181. package/dist/studio/web/.next/static/chunks/webpack-040077c7c5b63775.js +0 -1
  182. package/dist/studio/web/.next/static/css/b1a43ef7dccd6013.css +0 -1
  183. /package/dist/studio/web/.next/static/{d2gceAJH4KOAP1AWstMW0 → Ahppnr7sbzLwhsw77RqCy}/_buildManifest.js +0 -0
  184. /package/dist/studio/web/.next/static/{d2gceAJH4KOAP1AWstMW0 → Ahppnr7sbzLwhsw77RqCy}/_ssgManifest.js +0 -0
@@ -0,0 +1,27 @@
1
+ import type { NodeCoreContentStore } from '../../artifact-store/node-content-store.js';
2
+ import type { LocalTaskOutput } from '../../inputs/contracts/local-task.js';
3
+ export interface TaskAttemptDiagnostic {
4
+ readonly stage: 'execution' | 'acceptance';
5
+ readonly status: string;
6
+ readonly output: LocalTaskOutput;
7
+ readonly stdout: string;
8
+ readonly stderr: string;
9
+ readonly processOutcome: {
10
+ readonly exitCode: number | null;
11
+ readonly signal: string | null;
12
+ readonly failureKind: string | null;
13
+ } | null;
14
+ }
15
+ /** Host-only diagnostics use the existing content envelope, never an Execution success record. */
16
+ export declare function createTaskDiagnostics(store: NodeCoreContentStore, outputDirectory: string): {
17
+ capture(diagnostic: TaskAttemptDiagnostic): Promise<void>;
18
+ run<T>(runId: string, operation: () => Promise<T>): Promise<{
19
+ value: Awaited<T>;
20
+ references: {
21
+ mediaType: string;
22
+ digest: string;
23
+ size?: number | undefined;
24
+ uri?: string | undefined;
25
+ }[];
26
+ }>;
27
+ };
@@ -0,0 +1,30 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { join } from 'node:path';
3
+ import { digestCanonicalJson } from '../../../eval-core/contracts/index.js';
4
+ import { publishPrivateJsonExclusive } from '../../artifact-store/private-json-file.js';
5
+ /** Host-only diagnostics use the existing content envelope, never an Execution success record. */
6
+ export function createTaskDiagnostics(store, outputDirectory) {
7
+ const context = new AsyncLocalStorage();
8
+ return {
9
+ async capture(diagnostic) {
10
+ const current = context.getStore();
11
+ if (!current)
12
+ throw new Error('TASK_DIAGNOSTIC_CONTEXT_MISSING');
13
+ const value = { diagnosticKind: 'local-task-attempt', diagnosticVersion: 1,
14
+ runId: current.runId, capturedAt: new Date().toISOString(), ...diagnostic };
15
+ const reference = await store.put({ value, digest: digestCanonicalJson(value),
16
+ mediaType: 'application/json', classification: 'sensitive' });
17
+ const source = diagnostic.output.source;
18
+ const key = digestCanonicalJson({ ...source, stage: diagnostic.stage }).slice('sha256:'.length);
19
+ const publication = await publishPrivateJsonExclusive(join(outputDirectory, 'task-diagnostics', current.runId, `${key}.json`), { runId: current.runId, ...source, stage: diagnostic.stage, status: diagnostic.status, reference });
20
+ if (publication !== 'published')
21
+ throw new Error('TASK_DIAGNOSTIC_INDEX_EXISTS');
22
+ current.references.push(reference);
23
+ },
24
+ async run(runId, operation) {
25
+ const state = { runId, references: [] };
26
+ const value = await context.run(state, operation);
27
+ return { value, references: state.references };
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,19 @@
1
+ import { type JsonValue } from '../../../eval-core/contracts/index.js';
2
+ import type { Executor } from '../../../eval-runtime/evaluation/contracts.js';
3
+ import type { WorkspaceProvider } from '../../../eval-runtime/workspace.js';
4
+ import { type LocalTaskDefinition, type LocalTaskOutput, type TaskFile } from '../../inputs/contracts/local-task.js';
5
+ import type { TaskAttemptDiagnostic } from './diagnostics.js';
6
+ import { type CapturedIdentityFile } from '../adapters/shared/content-identity.js';
7
+ export declare function createTaskExecutor(input: {
8
+ definition: LocalTaskDefinition;
9
+ snapshot: readonly TaskFile[];
10
+ provider: WorkspaceProvider;
11
+ temporaryRoot: string;
12
+ executable: string;
13
+ executableDigest: string;
14
+ version: string;
15
+ identityFiles: readonly CapturedIdentityFile[];
16
+ fixtureSource?: string;
17
+ authenticationFile?: string;
18
+ captureDiagnostic: (diagnostic: TaskAttemptDiagnostic) => Promise<void>;
19
+ }): Executor<JsonValue, undefined, LocalTaskOutput>;
@@ -0,0 +1,135 @@
1
+ import { chmod, copyFile, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
2
+ import { delimiter, dirname, join } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { ExecutionPortFailure } from '../../../eval-core/execution/index.js';
5
+ import { spawnWithSigintPropagation } from '../../../executors/core/subprocess.js';
6
+ import { buildCodexExecArguments } from '../../../executors/openai/codex/cli-arguments.js';
7
+ import { parseCodexCliStream } from '../adapters/codex/cli-protocol.js';
8
+ import { LocalTaskOutputSchema } from '../../inputs/contracts/local-task.js';
9
+ import { collectTaskArtifacts, taskTreeDigest } from './files.js';
10
+ import { assertIdentityFilesUnchanged } from '../adapters/shared/content-identity.js';
11
+ export function createTaskExecutor(input) {
12
+ const { definition } = input;
13
+ const snapshotDigest = taskTreeDigest(input.snapshot);
14
+ return {
15
+ executorId: 'omk.local-task-executor/v1', version: '1.1.0',
16
+ schemas: { input: z.json(), output: LocalTaskOutputSchema, trace: z.json() },
17
+ outputClassification: 'sensitive', traceClassification: 'sensitive',
18
+ outputMediaType: 'application/vnd.omk.local-task-output+json',
19
+ workspaceProvider: input.provider,
20
+ capabilities: {
21
+ determinism: definition.execution.runtimeKind === 'fixture' ? 'deterministic' : 'stochastic',
22
+ cancellation: 'best-effort', concurrency: { safety: 'serialized', maxInFlight: 1 },
23
+ seedControl: 'unsupported', telemetry: { trace: 'optional', usage: 'optional', providerCost: { reporting: 'unsupported' } },
24
+ },
25
+ fingerprintFacets: {
26
+ diagnosticsPolicy: 'attempt-snapshot/v1', maxStreamBytes: 10 * 1024 * 1024,
27
+ outputSchema: 'omk.local-task-output/v1', runtimeKind: definition.execution.runtimeKind,
28
+ implementationDigest: input.executableDigest, runtimeVersion: input.version,
29
+ dependencies: input.identityFiles.map(({ facetId, digest, size }) => ({ facetId, digest, size })),
30
+ platform: process.platform, architecture: process.arch, nodeVersion: process.version,
31
+ model: definition.execution.runtimeKind === 'codex' ? definition.execution.model : 'offline-fixture',
32
+ effort: definition.execution.runtimeKind === 'codex' ? definition.execution.effort : 'none',
33
+ timeoutMs: definition.execution.timeoutMs, artifacts: definition.artifacts,
34
+ knowledgeMode: 'provided-content', sandbox: 'trusted-local-workspace-write',
35
+ environment: { LANG: 'C', TZ: 'UTC', inheritance: 'none', home: 'attempt-private' },
36
+ },
37
+ async execute(invocation) {
38
+ if (invocation.workspace === undefined)
39
+ return { errorCode: 'TASK_WORKSPACE_MISSING' };
40
+ invocation.signal.throwIfAborted();
41
+ const privateRoot = await mkdtemp(join(input.temporaryRoot, 'executor-'));
42
+ let stdout = '';
43
+ let stderr = '';
44
+ let processOutcome = null;
45
+ let status = 'TASK_EXECUTION_FAILED';
46
+ let captured;
47
+ const collect = async (response) => ({
48
+ schemaVersion: 'omk.local-task-output/v1', response, snapshotDigest,
49
+ ...await collectTaskArtifacts({ root: invocation.workspace.root, paths: definition.artifacts.files,
50
+ maxBytes: definition.artifacts.maxBytes, snapshot: input.snapshot }),
51
+ source: { sampleId: invocation.sampleId, variantId: invocation.variantId,
52
+ trialIndex: invocation.trialIndex, attemptNumber: invocation.attemptNumber },
53
+ });
54
+ try {
55
+ await assertIdentityFilesUnchanged(input.identityFiles, { adapterLabel: 'Local task',
56
+ cancellationCode: 'TASK_CANCELLED', identityChangedCode: 'TASK_EXECUTOR_CHANGED', signal: invocation.signal });
57
+ const env = { HOME: privateRoot, LANG: 'C', TZ: 'UTC', TMPDIR: privateRoot, PATH: [dirname(process.execPath), '/usr/bin', '/bin'].join(delimiter) };
58
+ const execution = definition.execution;
59
+ let args;
60
+ let command;
61
+ let stdin = '';
62
+ if (execution.runtimeKind === 'fixture') {
63
+ const script = join(privateRoot, 'fixture.mjs');
64
+ await writeFile(script, input.fixtureSource, { mode: 0o600 });
65
+ command = process.execPath;
66
+ args = [script];
67
+ stdin = JSON.stringify({ input: invocation.input, knowledge: invocation.artifact.content });
68
+ }
69
+ else {
70
+ const codexHome = join(privateRoot, 'codex');
71
+ await mkdir(codexHome, { mode: 0o700 });
72
+ if (input.authenticationFile !== undefined) {
73
+ await copyFile(input.authenticationFile, join(codexHome, 'auth.json'));
74
+ await chmod(join(codexHome, 'auth.json'), 0o600);
75
+ }
76
+ env.CODEX_HOME = codexHome;
77
+ command = input.executable;
78
+ args = buildCodexExecArguments({
79
+ model: execution.model, effort: execution.effort, workingDirectory: invocation.workspace.root,
80
+ prompt: `${invocation.artifact.content ?? ''}\n\n${String(invocation.input.text)}`,
81
+ sandbox: 'workspace-write', strictConfig: true, color: 'never', shellEnvironmentInheritance: 'none',
82
+ });
83
+ }
84
+ const { child, done } = spawnWithSigintPropagation(command, args, {
85
+ cwd: invocation.workspace.root, env, abortSignal: invocation.signal,
86
+ timeoutMs: execution.timeoutMs, maxBuffer: 10 * 1024 * 1024,
87
+ });
88
+ child.stdin?.on('error', () => { });
89
+ child.stdin?.end(stdin);
90
+ const completed = await done;
91
+ stdout = completed.stdout;
92
+ stderr = completed.stderr;
93
+ processOutcome = { exitCode: completed.code, signal: completed.signal, failureKind: null };
94
+ const parsed = execution.runtimeKind === 'codex' ? parseCodexCliStream(completed.stdout) : undefined;
95
+ if (parsed?.terminalStatus === 'failed')
96
+ return { errorCode: 'TASK_EXECUTION_FAILED', ...(parsed.usage ? { usage: parsed.usage } : {}) };
97
+ const output = await collect(parsed?.output ?? completed.stdout);
98
+ captured = output;
99
+ status = 'completed';
100
+ return { output, ...(parsed?.trace === undefined ? {} : { trace: parsed.trace }),
101
+ ...(parsed?.usage === undefined ? {} : { usage: parsed.usage }) };
102
+ }
103
+ catch (error) {
104
+ const failure = error;
105
+ stdout = failure.stdout ?? stdout;
106
+ stderr = failure.stderr ?? stderr;
107
+ if (failure.failureKind)
108
+ processOutcome = { exitCode: failure.code ?? null, signal: failure.signal ?? null, failureKind: failure.failureKind };
109
+ status = failure.killedByTimeout || invocation.signal.reason === 'timeout' ? 'TASK_EXECUTION_TIMEOUT'
110
+ : invocation.signal.aborted ? 'TASK_CANCELLED'
111
+ : error instanceof ExecutionPortFailure ? error.evaluationError.code : 'TASK_EXECUTION_FAILED';
112
+ if (invocation.signal.aborted)
113
+ throw invocation.signal.reason;
114
+ if (error instanceof ExecutionPortFailure)
115
+ throw error;
116
+ return { errorCode: status };
117
+ }
118
+ finally {
119
+ try {
120
+ if (invocation.signal.aborted)
121
+ status = invocation.signal.reason === 'timeout' ? 'TASK_EXECUTION_TIMEOUT' : 'TASK_CANCELLED';
122
+ await input.captureDiagnostic({ stage: 'execution', status, output: captured ?? await collect(''), stdout, stderr, processOutcome });
123
+ }
124
+ catch {
125
+ throw new ExecutionPortFailure({ code: 'TASK_DIAGNOSTIC_WRITE_FAILED', stage: 'infrastructure',
126
+ message: 'Local task diagnostic evidence could not be persisted.' });
127
+ }
128
+ finally {
129
+ // Diagnostic persistence must not prevent private credential cleanup.
130
+ await rm(privateRoot, { recursive: true, force: true });
131
+ }
132
+ }
133
+ },
134
+ };
135
+ }
@@ -0,0 +1,15 @@
1
+ import { type Sha256Digest } from '../../../eval-core/contracts/index.js';
2
+ import { type TaskFile, type LocalTaskOutput } from '../../inputs/contracts/local-task.js';
3
+ export declare function fileDigest(bytes: Uint8Array): Sha256Digest;
4
+ /** Explicit files only. A trusted local process is required; this is not a hostile-code sandbox. */
5
+ export declare function readTaskFile(root: string, path: string, maxBytes: number): Promise<TaskFile>;
6
+ export declare function captureTaskFiles(root: string, paths: readonly string[], maxBytes: number): Promise<readonly TaskFile[]>;
7
+ export declare function taskTreeDigest(files: readonly TaskFile[]): Sha256Digest;
8
+ /** Only used with a fresh host-owned directory, never an Agent's writable tree. */
9
+ export declare function materializeTaskFiles(root: string, files: readonly TaskFile[]): Promise<void>;
10
+ export declare function collectTaskArtifacts(input: {
11
+ root: string;
12
+ paths: readonly string[];
13
+ maxBytes: number;
14
+ snapshot: readonly TaskFile[];
15
+ }): Promise<Pick<LocalTaskOutput, 'files' | 'missing' | 'collectionErrors'>>;
@@ -0,0 +1,88 @@
1
+ import { constants } from 'node:fs';
2
+ import { lstat, mkdir, open, writeFile } from 'node:fs/promises';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { digestCanonicalJson } from '../../../eval-core/contracts/index.js';
6
+ import { LocalTaskPathSchema } from '../../inputs/contracts/local-task.js';
7
+ export function fileDigest(bytes) {
8
+ return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
9
+ }
10
+ /** Explicit files only. A trusted local process is required; this is not a hostile-code sandbox. */
11
+ export async function readTaskFile(root, path, maxBytes) {
12
+ LocalTaskPathSchema.parse(path);
13
+ let parent = resolve(root);
14
+ for (const part of ['', ...path.split('/').slice(0, -1)]) {
15
+ parent = join(parent, part);
16
+ const metadata = await lstat(parent);
17
+ if (!metadata.isDirectory() || metadata.isSymbolicLink())
18
+ throw new Error('TASK_PATH_UNSAFE');
19
+ }
20
+ const handle = await open(join(root, path), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
21
+ try {
22
+ const metadata = await handle.stat();
23
+ if (!metadata.isFile())
24
+ throw new Error('TASK_PATH_UNSAFE');
25
+ if (metadata.size > maxBytes)
26
+ throw new Error('TASK_FILE_LIMIT');
27
+ // Bound the actual read, including a file growing after stat().
28
+ const buffer = Buffer.alloc(maxBytes + 1);
29
+ let length = 0;
30
+ while (length < buffer.length) {
31
+ const { bytesRead } = await handle.read(buffer, length, buffer.length - length, length);
32
+ if (bytesRead === 0)
33
+ break;
34
+ length += bytesRead;
35
+ }
36
+ if (length > maxBytes)
37
+ throw new Error('TASK_FILE_LIMIT');
38
+ const bytes = buffer.subarray(0, length);
39
+ return { path, contentBase64: bytes.toString('base64'), digest: fileDigest(bytes), executable: (metadata.mode & 0o111) !== 0 };
40
+ }
41
+ finally {
42
+ await handle.close();
43
+ }
44
+ }
45
+ export async function captureTaskFiles(root, paths, maxBytes) {
46
+ const files = [];
47
+ let remaining = maxBytes;
48
+ for (const path of [...paths].sort()) {
49
+ const file = await readTaskFile(root, path, remaining);
50
+ remaining -= Buffer.from(file.contentBase64, 'base64').length;
51
+ files.push(file);
52
+ }
53
+ return Object.freeze(files.map((file) => Object.freeze(file)));
54
+ }
55
+ export function taskTreeDigest(files) {
56
+ return digestCanonicalJson([...files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
57
+ }
58
+ /** Only used with a fresh host-owned directory, never an Agent's writable tree. */
59
+ export async function materializeTaskFiles(root, files) {
60
+ for (const file of files) {
61
+ LocalTaskPathSchema.parse(file.path);
62
+ const bytes = Buffer.from(file.contentBase64, 'base64');
63
+ if (bytes.toString('base64') !== file.contentBase64 || fileDigest(bytes) !== file.digest)
64
+ throw new Error('TASK_FILE_DIGEST_INVALID');
65
+ const destination = join(root, file.path);
66
+ await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
67
+ await writeFile(destination, bytes, { flag: 'wx', mode: file.executable ? 0o700 : 0o600 });
68
+ }
69
+ }
70
+ export async function collectTaskArtifacts(input) {
71
+ const result = { files: [], missing: [], collectionErrors: [] };
72
+ let remaining = input.maxBytes;
73
+ for (const path of [...input.paths].sort()) {
74
+ try {
75
+ const file = await readTaskFile(input.root, path, remaining);
76
+ remaining -= Buffer.from(file.contentBase64, 'base64').length;
77
+ const before = input.snapshot.find((entry) => entry.path === path);
78
+ result.files.push({ ...file, change: before === undefined ? 'added' : before.digest === file.digest && before.executable === file.executable ? 'unchanged' : 'modified' });
79
+ }
80
+ catch (error) {
81
+ if (error.code === 'ENOENT')
82
+ result.missing.push(path);
83
+ else
84
+ result.collectionErrors.push({ path, code: error instanceof Error && error.message === 'TASK_FILE_LIMIT' ? 'TASK_FILE_LIMIT' : 'TASK_COLLECTION_FAILED' });
85
+ }
86
+ }
87
+ return result;
88
+ }
@@ -0,0 +1,6 @@
1
+ import type { WorkspaceDescriptor, WorkspaceProvider } from '../../../eval-runtime/workspace.js';
2
+ import type { TaskFile } from '../../inputs/contracts/local-task.js';
3
+ export declare function createTaskWorkspace(files: readonly TaskFile[], temporaryRoot: string): {
4
+ descriptor: WorkspaceDescriptor;
5
+ provider: WorkspaceProvider;
6
+ };
@@ -0,0 +1,32 @@
1
+ import { mkdtemp, rm } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { materializeTaskFiles, taskTreeDigest } from './files.js';
4
+ export function createTaskWorkspace(files, temporaryRoot) {
5
+ const digest = taskTreeDigest(files);
6
+ const descriptor = {
7
+ resourceId: 'local-task-snapshot', digest, mediaType: 'application/vnd.omk.local-task-tree',
8
+ classification: 'sensitive', size: files.reduce((size, file) => size + Buffer.from(file.contentBase64, 'base64').length, 0),
9
+ };
10
+ return {
11
+ descriptor,
12
+ provider: {
13
+ providerId: 'omk.local-task-workspace/v1', version: '1.0.0',
14
+ fingerprintFacets: { snapshotDigest: digest, retryState: 'shared-within-trial' },
15
+ async open(request) {
16
+ request.signal.throwIfAborted();
17
+ if (request.descriptor.digest !== digest)
18
+ throw new Error('TASK_SNAPSHOT_MISMATCH');
19
+ const root = await mkdtemp(join(temporaryRoot, 'trial-'));
20
+ try {
21
+ await materializeTaskFiles(root, files);
22
+ request.signal.throwIfAborted();
23
+ return { root, close: () => rm(root, { recursive: true, force: true }) };
24
+ }
25
+ catch (error) {
26
+ await rm(root, { recursive: true, force: true });
27
+ throw error;
28
+ }
29
+ },
30
+ },
31
+ };
32
+ }
@@ -0,0 +1,46 @@
1
+ import { z } from 'zod';
2
+ export declare const LocalTaskPathSchema: z.ZodString;
3
+ export declare const TaskFileSchema: z.ZodObject<{
4
+ path: z.ZodString;
5
+ contentBase64: z.ZodString;
6
+ digest: z.ZodString;
7
+ executable: z.ZodBoolean;
8
+ }, z.core.$strict>;
9
+ export type TaskFile = z.infer<typeof TaskFileSchema>;
10
+ export declare const LocalTaskOutputSchema: z.ZodObject<{
11
+ schemaVersion: z.ZodLiteral<"omk.local-task-output/v1">;
12
+ response: z.ZodString;
13
+ snapshotDigest: z.ZodString;
14
+ files: z.ZodArray<z.ZodObject<{
15
+ path: z.ZodString;
16
+ contentBase64: z.ZodString;
17
+ digest: z.ZodString;
18
+ executable: z.ZodBoolean;
19
+ change: z.ZodEnum<{
20
+ unchanged: "unchanged";
21
+ modified: "modified";
22
+ added: "added";
23
+ }>;
24
+ }, z.core.$strict>>;
25
+ missing: z.ZodArray<z.ZodString>;
26
+ collectionErrors: z.ZodArray<z.ZodObject<{
27
+ path: z.ZodString;
28
+ code: z.ZodString;
29
+ }, z.core.$strict>>;
30
+ source: z.ZodObject<{
31
+ sampleId: z.ZodString;
32
+ variantId: z.ZodString;
33
+ trialIndex: z.ZodNumber;
34
+ attemptNumber: z.ZodNumber;
35
+ }, z.core.$strict>;
36
+ }, z.core.$strict>;
37
+ export type LocalTaskOutput = z.infer<typeof LocalTaskOutputSchema>;
38
+ export declare const LocalTaskAcceptanceSchema: z.ZodObject<{
39
+ schemaVersion: z.ZodLiteral<"omk.local-task-acceptance/v1">;
40
+ passed: z.ZodBoolean;
41
+ checks: z.ZodArray<z.ZodObject<{
42
+ checkId: z.ZodString;
43
+ passed: z.ZodBoolean;
44
+ detail: z.ZodString;
45
+ }, z.core.$strict>>;
46
+ }, z.core.$strict>;
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ import { Sha256DigestSchema } from '../../../eval-core/contracts/index.js';
3
+ export const LocalTaskPathSchema = z.string().min(1).max(1024).refine((path) => (!path.includes('\\') && !path.includes(':') && !/[\x00-\x1f]/.test(path)
4
+ && path.split('/').every((part) => part !== '' && part !== '.' && part !== '..'
5
+ && !/^(?:\.git|\.ssh|\.aws|\.azure|\.config|\.codex|\.claude|\.env(?:\..*)?|.*\.(?:pem|key)|credentials(?:\..*)?|auth\.json)$/i.test(part))), 'Expected a relative non-sensitive file path without traversal.');
6
+ export const TaskFileSchema = z.strictObject({
7
+ path: LocalTaskPathSchema,
8
+ contentBase64: z.string(),
9
+ digest: Sha256DigestSchema,
10
+ executable: z.boolean(),
11
+ });
12
+ export const LocalTaskOutputSchema = z.strictObject({
13
+ schemaVersion: z.literal('omk.local-task-output/v1'),
14
+ response: z.string(),
15
+ snapshotDigest: Sha256DigestSchema,
16
+ files: z.array(TaskFileSchema.extend({ change: z.enum(['unchanged', 'modified', 'added']) })),
17
+ missing: z.array(LocalTaskPathSchema),
18
+ collectionErrors: z.array(z.strictObject({ path: LocalTaskPathSchema, code: z.string() })),
19
+ source: z.strictObject({ sampleId: z.string(), variantId: z.string(), trialIndex: z.number().int(), attemptNumber: z.number().int() }),
20
+ });
21
+ export const LocalTaskAcceptanceSchema = z.strictObject({
22
+ schemaVersion: z.literal('omk.local-task-acceptance/v1'),
23
+ passed: z.boolean(),
24
+ checks: z.array(z.strictObject({ checkId: z.string().min(1), passed: z.boolean(), detail: z.string().max(4000) })).min(1),
25
+ }).refine((value) => value.passed === value.checks.every((check) => check.passed), 'Overall result must match checks.')
26
+ .refine((value) => new Set(value.checks.map((check) => check.checkId)).size === value.checks.length, 'Duplicate check IDs.');
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod';
2
+ export * from './local-task-evidence.js';
3
+ export declare const LocalTaskDefinitionSchema: z.ZodObject<{
4
+ schemaVersion: z.ZodLiteral<"omk.local-task/v1">;
5
+ taskId: z.ZodString;
6
+ trust: z.ZodLiteral<"trusted-local">;
7
+ samples: z.ZodType<import("./sample.js").EvalSampleSetDocument, unknown, z.core.$ZodTypeInternals<import("./sample.js").EvalSampleSetDocument, unknown>>;
8
+ snapshot: z.ZodObject<{
9
+ root: z.ZodString;
10
+ files: z.ZodArray<z.ZodString>;
11
+ }, z.core.$strict>;
12
+ artifacts: z.ZodObject<{
13
+ files: z.ZodArray<z.ZodString>;
14
+ maxBytes: z.ZodNumber;
15
+ }, z.core.$strict>;
16
+ variants: z.ZodObject<{
17
+ control: z.ZodString;
18
+ treatment: z.ZodString;
19
+ }, z.core.$strict>;
20
+ execution: z.ZodDiscriminatedUnion<[z.ZodObject<{
21
+ runtimeKind: z.ZodLiteral<"codex">;
22
+ executable: z.ZodString;
23
+ model: z.ZodString;
24
+ effort: z.ZodEnum<{
25
+ max: "max";
26
+ low: "low";
27
+ medium: "medium";
28
+ high: "high";
29
+ xhigh: "xhigh";
30
+ }>;
31
+ timeoutMs: z.ZodNumber;
32
+ identityFiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
33
+ facetId: z.ZodString;
34
+ path: z.ZodString;
35
+ }, z.core.$strict>>>;
36
+ }, z.core.$strict>, z.ZodObject<{
37
+ runtimeKind: z.ZodLiteral<"fixture">;
38
+ script: z.ZodString;
39
+ timeoutMs: z.ZodNumber;
40
+ }, z.core.$strict>], "runtimeKind">;
41
+ acceptance: z.ZodObject<{
42
+ root: z.ZodString;
43
+ files: z.ZodArray<z.ZodString>;
44
+ entrypoint: z.ZodString;
45
+ timeoutMs: z.ZodNumber;
46
+ }, z.core.$strict>;
47
+ trials: z.ZodDefault<z.ZodNumber>;
48
+ seed: z.ZodDefault<z.ZodString>;
49
+ }, z.core.$strict>;
50
+ export type LocalTaskDefinition = z.infer<typeof LocalTaskDefinitionSchema>;
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+ import { EvalSampleSetDocumentSchema } from '../schemas/sample-set.js';
3
+ import { LocalTaskPathSchema } from './local-task-evidence.js';
4
+ export * from './local-task-evidence.js';
5
+ const FilesSchema = z.array(LocalTaskPathSchema).min(1).max(256)
6
+ .refine((paths) => new Set(paths).size === paths.length, 'Duplicate file paths.');
7
+ export const LocalTaskDefinitionSchema = z.strictObject({
8
+ schemaVersion: z.literal('omk.local-task/v1'),
9
+ taskId: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/),
10
+ trust: z.literal('trusted-local'),
11
+ samples: EvalSampleSetDocumentSchema,
12
+ snapshot: z.strictObject({ root: z.string().min(1), files: FilesSchema }),
13
+ artifacts: z.strictObject({ files: FilesSchema, maxBytes: z.number().int().positive().max(16 * 1024 * 1024) }),
14
+ variants: z.strictObject({ control: z.string().min(1), treatment: z.string().min(1) }),
15
+ execution: z.discriminatedUnion('runtimeKind', [
16
+ z.strictObject({
17
+ runtimeKind: z.literal('codex'), executable: z.string().min(1), model: z.string().min(1),
18
+ effort: z.enum(['low', 'medium', 'high', 'xhigh', 'max']),
19
+ timeoutMs: z.number().int().positive(),
20
+ identityFiles: z.array(z.strictObject({ facetId: z.string().min(1), path: z.string().min(1) })).default([]),
21
+ }),
22
+ z.strictObject({
23
+ runtimeKind: z.literal('fixture'), script: z.string().min(1),
24
+ timeoutMs: z.number().int().positive(),
25
+ }),
26
+ ]),
27
+ acceptance: z.strictObject({
28
+ root: z.string().min(1), files: FilesSchema, entrypoint: LocalTaskPathSchema,
29
+ timeoutMs: z.number().int().positive(),
30
+ }).refine((value) => value.files.includes(value.entrypoint), 'Entrypoint must be included in acceptance files.'),
31
+ trials: z.number().int().positive().max(100).default(1),
32
+ seed: z.string().min(1).default('local-task-v1'),
33
+ });
@@ -0,0 +1,23 @@
1
+ import type { CapturedContent } from '../../eval-core/contracts/index.js';
2
+ /** Only declared file metadata reaches Studio; source bytes and Agent prose stay in raw evidence. */
3
+ export declare function projectLocalTaskOutput(content: CapturedContent | undefined): {
4
+ snapshotDigest: string;
5
+ files: {
6
+ path: string;
7
+ digest: string;
8
+ change: "unchanged" | "modified" | "added";
9
+ }[];
10
+ missing: string[];
11
+ collectionErrors: {
12
+ path: string;
13
+ code: string;
14
+ }[];
15
+ } | undefined;
16
+ export declare function projectLocalTaskAcceptance(content: CapturedContent | undefined): {
17
+ acceptanceDigest: string;
18
+ passed: boolean;
19
+ checks: {
20
+ checkId: string;
21
+ passed: boolean;
22
+ }[];
23
+ } | undefined;
@@ -0,0 +1,25 @@
1
+ import { LocalTaskAcceptanceSchema, LocalTaskOutputSchema } from '../inputs/contracts/local-task-evidence.js';
2
+ /** Only declared file metadata reaches Studio; source bytes and Agent prose stay in raw evidence. */
3
+ export function projectLocalTaskOutput(content) {
4
+ if (content?.contentKind !== 'inline' || content.classification === 'secret' || content.classification === 'gold')
5
+ return undefined;
6
+ const parsed = LocalTaskOutputSchema.safeParse(content.value);
7
+ if (!parsed.success)
8
+ return undefined;
9
+ return {
10
+ snapshotDigest: parsed.data.snapshotDigest,
11
+ files: parsed.data.files.map(({ path, digest, change }) => ({ path, digest, change })),
12
+ missing: parsed.data.missing,
13
+ collectionErrors: parsed.data.collectionErrors,
14
+ };
15
+ }
16
+ export function projectLocalTaskAcceptance(content) {
17
+ if (content?.contentKind !== 'inline' || content.classification === 'secret' || content.classification === 'gold'
18
+ || content.value === null || typeof content.value !== 'object' || Array.isArray(content.value))
19
+ return undefined;
20
+ const { acceptanceDigest, ...value } = content.value;
21
+ const parsed = LocalTaskAcceptanceSchema.safeParse(value);
22
+ if (!parsed.success || typeof acceptanceDigest !== 'string' || !/^sha256:[a-f0-9]{64}$/.test(acceptanceDigest))
23
+ return undefined;
24
+ return { acceptanceDigest, passed: parsed.data.passed, checks: parsed.data.checks.map(({ checkId, passed }) => ({ checkId, passed })) };
25
+ }
@@ -89,7 +89,7 @@ export function extractCodexFinalOutput(events) {
89
89
  export function isCodexReconnectNotice(event) {
90
90
  if (event.type !== 'error' || typeof event.message !== 'string')
91
91
  return false;
92
- const match = /^Reconnecting\.\.\. ([1-9]\d*)\/([1-9]\d*) \(stream disconnected before completion: .+\)$/.exec(event.message);
92
+ const match = /^Reconnecting\.\.\. ([1-9]\d*)\/([1-9]\d*) \((?:stream disconnected before completion: .+|request timed out)\)$/.exec(event.message);
93
93
  return match !== null && Number.isSafeInteger(Number(match[1]))
94
94
  && Number.isSafeInteger(Number(match[2])) && Number(match[1]) <= Number(match[2]);
95
95
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  /** Canonical user-facing API. Advanced surfaces use explicit package subpaths. */
2
2
  export * from './eval-runtime/index.js';
3
3
  export * from './eval-workflows/hosts/reference-executors.js';
4
+ export { prepareLocalTask, type LocalTaskOptions } from './eval-workflows/hosts/local-task/application.js';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  /** Canonical user-facing API. Advanced surfaces use explicit package subpaths. */
2
2
  export * from './eval-runtime/index.js';
3
3
  export * from './eval-workflows/hosts/reference-executors.js';
4
+ export { prepareLocalTask } from './eval-workflows/hosts/local-task/application.js';
@@ -40,9 +40,9 @@ export declare const KnowledgeContentSchema: z.ZodObject<{
40
40
  entityId: z.ZodString;
41
41
  }, z.core.$strict>>;
42
42
  modality: z.ZodEnum<{
43
+ capability: "capability";
43
44
  descriptive: "descriptive";
44
45
  normative: "normative";
45
- capability: "capability";
46
46
  permission: "permission";
47
47
  }>;
48
48
  polarity: z.ZodEnum<{
@@ -160,9 +160,9 @@ export declare const KnowledgeDraftSchema: z.ZodObject<{
160
160
  entityId: z.ZodString;
161
161
  }, z.core.$strict>>;
162
162
  modality: z.ZodEnum<{
163
+ capability: "capability";
163
164
  descriptive: "descriptive";
164
165
  normative: "normative";
165
- capability: "capability";
166
166
  permission: "permission";
167
167
  }>;
168
168
  polarity: z.ZodEnum<{
@@ -294,9 +294,9 @@ export declare const KnowledgeRevisionSchema: z.ZodObject<{
294
294
  entityId: z.ZodString;
295
295
  }, z.core.$strict>>;
296
296
  modality: z.ZodEnum<{
297
+ capability: "capability";
297
298
  descriptive: "descriptive";
298
299
  normative: "normative";
299
- capability: "capability";
300
300
  permission: "permission";
301
301
  }>;
302
302
  polarity: z.ZodEnum<{
@@ -469,8 +469,8 @@ export declare const EntityMentionSchema: z.ZodObject<{
469
469
  quote: z.ZodString;
470
470
  }, z.core.$strict>;
471
471
  basis: z.ZodEnum<{
472
- inference: "inference";
473
472
  explicit: "explicit";
473
+ inference: "inference";
474
474
  }>;
475
475
  rationale: z.ZodString;
476
476
  }, z.core.$strict>;