@akagilnc/pi-workflow-roles 0.1.5577 → 0.1.5593

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.
@@ -344,7 +344,7 @@ const SHARED_PROJECT_SEMANTICS = {
344
344
  } as const satisfies Omit<PublicOptionDefinition, "owner">;
345
345
 
346
346
  /**
347
- * Immutable shared semantics for the common frozen-file `--attach` face.
347
+ * Immutable shared semantics for the common `--attach` face (#1165).
348
348
  * Role rows bind owner only. Reviewer has no attach face; analyst sweep attach
349
349
  * keeps its own modes/selectsMode/description and must not use this binding.
350
350
  */
@@ -357,8 +357,8 @@ const SHARED_ATTACH_SEMANTICS = {
357
357
  repeatable: true,
358
358
  form: "option" as const,
359
359
  description: {
360
- en: "Attach a regular file; frozen at admission (repeatable).",
361
- zh: "附加普通文件;受理即冻结(可重复)。",
360
+ en: "Caller file path passed as-is to the role (repeatable). Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
361
+ zh: "调用方文件路径原样递给衙门(可重复)。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
362
362
  },
363
363
  } as const satisfies Omit<PublicOptionDefinition, "owner">;
364
364
 
@@ -556,8 +556,8 @@ const COLLECTOR_OPTIONS = [
556
556
  repeatable: false,
557
557
  form: "option",
558
558
  description: {
559
- en: "Optional request manifest JSON path ({requests:[{id,body}]}). Parsed for semantics and passed to the Collector as materials — not a machine collection directive.",
560
- zh: "可选 request manifest JSON 路径({requests:[{id,body}]})。按语义解析后作为材料递给通进司,不是机器代收 finding 的指令。",
559
+ en: "Caller path to a request manifest JSON file, passed as-is. Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
560
+ zh: "调用方 request manifest JSON 路径,原样传递。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
561
561
  },
562
562
  },
563
563
  ] as const satisfies readonly PublicOptionDefinition[];
@@ -7,7 +7,6 @@
7
7
  */
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { writeFile } from "node:fs/promises";
10
- import { isAbsolute, join, resolve } from "node:path";
11
10
 
12
11
  import {
13
12
  buildAutoResumeContinuationPrompt,
@@ -22,13 +21,10 @@ import { projectPublicTurnAxes, type RoleTurnRequestProjectionOptions } from "./
22
21
  import {
23
22
  bindAdmittedTicketNumber,
24
23
  buildInstructionTransportPrompt,
25
- freezeAttachmentsIntoRun,
26
24
  relocateAdmittedRunToTicket,
27
25
  } from "./invocation.ts";
28
26
  import { readRecordedSubmissionRows } from "../submission-ledger.ts";
29
27
  import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.ts";
30
- import { pathContainedIn } from "../activation-ledger-topology.ts";
31
- import { pickEngineAxis } from "../package-resources/engine-material.ts";
32
28
  import { readStoredHostSessionId } from "../session-identity.ts";
33
29
  import { reportRunRecord } from "../sitian-facade.ts";
34
30
  import {
@@ -136,10 +132,11 @@ function projectRelocatedTurnIdentity(
136
132
  mutableRequest.principal = admitted.principal;
137
133
  const activation = mutableRequest.activation;
138
134
  if (isRecord(activation)) {
139
- for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath", "requestManifestPath"] as const) {
135
+ for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath"] as const) {
140
136
  const record = activation as Record<string, unknown>;
141
137
  if (field in record) record[field] = rewrite(record[field]);
142
138
  }
139
+ // #1165: activation.requestManifestPath is a caller path — do not rewrite.
143
140
  }
144
141
  if (result.terminal !== undefined) {
145
142
  for (const artifact of result.terminal.artifacts) {
@@ -1477,7 +1474,7 @@ export function resumeTurnRequestProjectionOptions(
1477
1474
  summonsPrepared?: {
1478
1475
  readonly instruction: string;
1479
1476
  readonly instructionEmpty: boolean;
1480
- readonly attachments: readonly { frozenPath: string }[];
1477
+ readonly attachments: readonly { path: string }[];
1481
1478
  },
1482
1479
  ): RoleTurnRequestProjectionOptions {
1483
1480
  // #879: officer dialogue content is caller/peer words only — no「请重读」,
@@ -1488,7 +1485,7 @@ export function resumeTurnRequestProjectionOptions(
1488
1485
  if (request.message !== undefined) {
1489
1486
  if (summonsPrepared !== undefined) {
1490
1487
  // #755: same-ticket review / open-court — caller words.
1491
- // #879 station-child officer: words only (attachments are independent freeze).
1488
+ // #879 station-child officer: words only (paths remain on summons materials).
1492
1489
  prompt = officerDialogue
1493
1490
  ? request.message
1494
1491
  : buildInstructionTransportPrompt({
@@ -1505,8 +1502,10 @@ export function resumeTurnRequestProjectionOptions(
1505
1502
  } else if (summonsPrepared !== undefined) {
1506
1503
  // #879 station-child officer: instruction bytes === peer body/reask (no wrap).
1507
1504
  // Other seats keep #755 instruction + optional attachment path listing.
1505
+ // #1165 J3: officer dialogue is raw instruction bytes; do not gate on
1506
+ // instructionEmpty metadata (resume of older admitted pages).
1508
1507
  prompt = officerDialogue
1509
- ? (summonsPrepared.instructionEmpty ? "" : summonsPrepared.instruction)
1508
+ ? summonsPrepared.instruction
1510
1509
  : buildInstructionTransportPrompt(summonsPrepared);
1511
1510
  } else if (request.summons !== undefined) {
1512
1511
  // #879: same-ticket summons with no instruction (e.g. notary source-run binding
@@ -1635,31 +1634,17 @@ async function runSettledAutoResumeLoop<
1635
1634
  });
1636
1635
  }
1637
1636
 
1638
- function isAlreadyFrozenSummonsAttachment(
1639
- runDirectory: string,
1640
- attachmentPath: string,
1641
- ): boolean {
1642
- const absolute = isAbsolute(attachmentPath)
1643
- ? attachmentPath
1644
- : resolve(attachmentPath);
1645
- return pathContainedIn(join(runDirectory, "attachments"), absolute);
1646
- }
1647
-
1648
1637
  /**
1649
- * Freeze same-ticket summons attachments into the retained run directory (#637).
1650
- * No-op materials (no paths / instruction-only) skip the freeze.
1651
- * Paths already under this run's attachments/ are the accepted freeze identity —
1652
- * reuse them for the same internal re-summons flow.
1653
- * Manual resume never calls this — old attachment semantics stay intact.
1638
+ * Same-ticket summons materials: caller paths as-is (#1165). No copy or freeze.
1654
1639
  */
1655
1640
  export async function prepareSummonsResumeMaterials(
1656
- runDirectory: string,
1641
+ _runDirectory: string,
1657
1642
  summons: SameTicketSummonsMaterials | undefined,
1658
1643
  ): Promise<
1659
1644
  | {
1660
1645
  readonly instruction: string;
1661
1646
  readonly instructionEmpty: boolean;
1662
- readonly attachments: readonly { frozenPath: string }[];
1647
+ readonly attachments: readonly { path: string }[];
1663
1648
  }
1664
1649
  | undefined
1665
1650
  > {
@@ -1669,16 +1654,8 @@ export async function prepareSummonsResumeMaterials(
1669
1654
  }
1670
1655
  const instruction = summons.instruction ?? "";
1671
1656
  const instructionEmpty =
1672
- summons.instructionEmpty ?? instruction.trim() === "";
1673
- let attachments: readonly { frozenPath: string }[] = [];
1674
- if (summons.attachmentPaths !== undefined && summons.attachmentPaths.length > 0) {
1675
- const alreadyFrozen = summons.attachmentPaths.every((path) =>
1676
- isAlreadyFrozenSummonsAttachment(runDirectory, path),
1677
- );
1678
- attachments = alreadyFrozen
1679
- ? summons.attachmentPaths.map((frozenPath) => ({ frozenPath }))
1680
- : await freezeAttachmentsIntoRun(summons.attachmentPaths, runDirectory);
1681
- }
1657
+ summons.instructionEmpty ?? instruction.length === 0;
1658
+ const attachments = (summons.attachmentPaths ?? []).map((path) => ({ path }));
1682
1659
  return { instruction, instructionEmpty, attachments };
1683
1660
  }
1684
1661
 
@@ -1779,28 +1756,6 @@ export async function runPostAdmissionSeatResume<
1779
1756
  }
1780
1757
  }
1781
1758
 
1782
- // Internal re-summons freezes external paths once and records that identity.
1783
- if (request.summons !== undefined) {
1784
- const prepared = await prepareSummonsResumeMaterials(
1785
- admittedForBuild.runDirectory,
1786
- request.summons,
1787
- );
1788
- if (
1789
- prepared !== undefined &&
1790
- (request.summons.attachmentPaths?.length ?? 0) > 0
1791
- ) {
1792
- request = {
1793
- ...request,
1794
- summons: {
1795
- ...request.summons,
1796
- attachmentPaths: prepared.attachments.map(
1797
- (attachment) => attachment.frozenPath,
1798
- ),
1799
- },
1800
- };
1801
- }
1802
- }
1803
-
1804
1759
  // Public explicit resume: attach the stored native id when the caller
1805
1760
  // left it unset (399c3c8c). In-call auto-resume / 催交 / gate retry omit
1806
1761
  // the field; those load inside the host adapter (host-contracts).
@@ -2058,13 +2013,7 @@ export async function runPostAdmissionOneShot<
2058
2013
  ...input.request,
2059
2014
  continuation: {
2060
2015
  kind: "resume",
2061
- prompt: buildAutoResumeContinuationPrompt({
2062
- packageRoot: input.env.packageRoot,
2063
- ...pickEngineAxis({
2064
- engine: input.effectiveEngine ?? input.env.engine,
2065
- engineModel: input.env.engineModel,
2066
- }),
2067
- }),
2016
+ prompt: buildAutoResumeContinuationPrompt(),
2068
2017
  },
2069
2018
  }),
2070
2019
  adapters: input.adapters,
@@ -29,11 +29,6 @@ import {
29
29
  rewriteAdmittedRoleRunPage,
30
30
  rewriteRunDirectoryPathValue,
31
31
  } from "../role-run-relocation.ts";
32
- import {
33
- appendEngineSessionMaterial,
34
- engineSessionMaterialFromOptions,
35
- pickEngineAxis,
36
- } from "../package-resources/engine-material.ts";
37
32
  import type { PublicThinkingLevel } from "./registry.ts";
38
33
  import {
39
34
  packagedResumeSourcePath,
@@ -58,6 +53,7 @@ import {
58
53
  type AdmittedRoleInvocation,
59
54
  type CoderPhase,
60
55
  type DerivedMergerEnvelope,
56
+ normalizeAdmittedAttachment,
61
57
  type FrozenAttachment,
62
58
  type InvocationEffectiveModel,
63
59
  type ReviewerLens,
@@ -137,21 +133,12 @@ export type SameTicketSummonsMaterials = {
137
133
 
138
134
  /**
139
135
  * Auto-resume continuation only (#959 / ADR 0080).
140
- * Always non-empty: Chinese neutral envelope plus optional engine pointers.
136
+ * Always non-empty Chinese neutral envelope. Engine / outsourcing material
137
+ * rides startup readingMaterial (#1167), never this continuation.
141
138
  * Never call this from manual `ak-role resume`.
142
139
  */
143
- export function buildAutoResumeContinuationPrompt(options: {
144
- packageRoot: string;
145
- engine?: string;
146
- engineModel?: string;
147
- }): string {
148
- return appendEngineSessionMaterial(
149
- [RESUME_TRANSPORT_ENVELOPE],
150
- engineSessionMaterialFromOptions({
151
- packageRoot: options.packageRoot,
152
- ...pickEngineAxis(options),
153
- }),
154
- ).join("\n");
140
+ export function buildAutoResumeContinuationPrompt(): string {
141
+ return RESUME_TRANSPORT_ENVELOPE;
155
142
  }
156
143
 
157
144
  const WRITER_LOCK_FILE = "writer.lock";
@@ -197,7 +184,7 @@ function parseSameTicketSummonsMaterials(
197
184
  const instructionEmpty =
198
185
  typeof record.instructionEmpty === "boolean" ? record.instructionEmpty : undefined;
199
186
  const attachmentPaths = Array.isArray(record.attachmentPaths)
200
- ? record.attachmentPaths.filter((p): p is string => typeof p === "string" && p.length > 0)
187
+ ? record.attachmentPaths.filter((p): p is string => typeof p === "string")
201
188
  : undefined;
202
189
  const sourceRunPath =
203
190
  typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== ""
@@ -1021,7 +1008,6 @@ type LoadedAdmittedRequestFields = {
1021
1008
  readonly repository?: string;
1022
1009
  readonly repositoryDisplay?: string;
1023
1010
  readonly requestManifestPath?: string;
1024
- readonly manifestDigest?: string;
1025
1011
  /** Collector wait-window ms restored on resume (#678). */
1026
1012
  readonly waitWindowMs?: number;
1027
1013
  /** Doctor — admitted single-case identity restored on resume (#633). */
@@ -1110,7 +1096,6 @@ async function loadResumableRunRecord(
1110
1096
  let repository: string | undefined;
1111
1097
  let repositoryDisplay: string | undefined;
1112
1098
  let requestManifestPath: string | undefined;
1113
- let manifestDigest: string | undefined;
1114
1099
  let waitWindowMs: number | undefined;
1115
1100
  let issueNumber: number | undefined;
1116
1101
  let caseRunsPath: string | undefined;
@@ -1136,7 +1121,9 @@ async function loadResumableRunRecord(
1136
1121
  instructionEmpty = record.instructionEmpty;
1137
1122
  }
1138
1123
  if (Array.isArray(record.attachments)) {
1139
- attachments = record.attachments as FrozenAttachment[];
1124
+ attachments = record.attachments
1125
+ .map((item) => normalizeAdmittedAttachment(item))
1126
+ .filter((item): item is FrozenAttachment => item !== undefined);
1140
1127
  }
1141
1128
  if (record.phase === "plan" || record.phase === "apply") {
1142
1129
  phase = record.phase;
@@ -1175,12 +1162,10 @@ async function loadResumableRunRecord(
1175
1162
  if (typeof record.repositoryDisplay === "string" && record.repositoryDisplay.trim() !== "") {
1176
1163
  repositoryDisplay = record.repositoryDisplay;
1177
1164
  }
1178
- if (typeof record.requestManifestPath === "string" && record.requestManifestPath.trim() !== "") {
1165
+ // #1165: opaque caller path on resume — do not trim-filter provided values.
1166
+ if (typeof record.requestManifestPath === "string") {
1179
1167
  requestManifestPath = record.requestManifestPath;
1180
1168
  }
1181
- if (typeof record.manifestDigest === "string" && record.manifestDigest.trim() !== "") {
1182
- manifestDigest = record.manifestDigest;
1183
- }
1184
1169
  if (typeof record.waitWindowMs === "number" && Number.isSafeInteger(record.waitWindowMs) && record.waitWindowMs >= 1) {
1185
1170
  waitWindowMs = record.waitWindowMs;
1186
1171
  }
@@ -1349,7 +1334,6 @@ async function loadResumableRunRecord(
1349
1334
  ...(repository === undefined ? {} : { repository }),
1350
1335
  ...(repositoryDisplay === undefined ? {} : { repositoryDisplay }),
1351
1336
  ...(requestManifestPath === undefined ? {} : { requestManifestPath }),
1352
- ...(manifestDigest === undefined ? {} : { manifestDigest }),
1353
1337
  ...(waitWindowMs === undefined ? {} : { waitWindowMs }),
1354
1338
  ...(issueNumber === undefined ? {} : { issueNumber }),
1355
1339
  ...(caseRunsPath === undefined ? {} : { caseRunsPath }),
@@ -1589,12 +1573,8 @@ function admitResumedRole(loaded: {
1589
1573
  return admitted;
1590
1574
  }
1591
1575
  case "collect-target": {
1592
- const { prNumber, repository, repositoryDisplay, manifestDigest } = fields;
1593
- if (
1594
- repository === undefined ||
1595
- repositoryDisplay === undefined ||
1596
- manifestDigest === undefined
1597
- ) {
1576
+ const { prNumber, repository, repositoryDisplay } = fields;
1577
+ if (repository === undefined || repositoryDisplay === undefined) {
1598
1578
  throw new CliUsageError(
1599
1579
  `role run admitted collector repository identity is missing: ${runId}`,
1600
1580
  );
@@ -1620,7 +1600,6 @@ function admitResumedRole(loaded: {
1620
1600
  ? {}
1621
1601
  : { requestManifestPath: fields.requestManifestPath }),
1622
1602
  ...(fields.waitWindowMs === undefined ? {} : { waitWindowMs: fields.waitWindowMs }),
1623
- manifestDigest,
1624
1603
  };
1625
1604
  return admitted;
1626
1605
  }
@@ -496,7 +496,7 @@ export async function summonPublicRole(
496
496
  runId: resumeRunId,
497
497
  summons: {
498
498
  instruction,
499
- instructionEmpty: instruction.trim() === "",
499
+ instructionEmpty: instruction.length === 0,
500
500
  },
501
501
  },
502
502
  env as never,
@@ -170,6 +170,5 @@ export function ensureRoleRunPlacement(
170
170
  ledgerHome: string,
171
171
  placement: RoleRunPlacement,
172
172
  ): void {
173
- // attachments/ appears only when something is frozen into it.
174
173
  ensureRoleRunDirectory(ledgerHome, placement.sessionDirectory);
175
174
  }
@@ -26,7 +26,7 @@ const ADMITTED_PAGE_FIELDS = [
26
26
  "taskPath",
27
27
  "packetPath",
28
28
  "prerequisitesPath",
29
- "requestManifestPath",
29
+ // #1165: requestManifestPath is a caller path — never rewrite.
30
30
  "mergerInputPath",
31
31
  "sourceRunPath",
32
32
  ] as const;
@@ -202,7 +202,7 @@ function rewriteSourceRunLocator(
202
202
  );
203
203
  }
204
204
 
205
- /** Same-ticket summons materials: typed source-run + frozen attachment pointers. */
205
+ /** Same-ticket summons materials: typed source-run; caller attach paths stay as-is (#1165). */
206
206
  function rewriteSummonsMaterials(
207
207
  value: unknown,
208
208
  rewrites: readonly RunDirectoryPathRewrite[],
@@ -214,12 +214,7 @@ function rewriteSummonsMaterials(
214
214
  rewrites,
215
215
  );
216
216
  rewriteSourceRunLocator(value.sourceRun, rewrites);
217
- // Bare-resume frozen attachment pointers (string[]), not free text / bytes.
218
- if (Array.isArray(value.attachmentPaths)) {
219
- value.attachmentPaths = value.attachmentPaths.map((path) =>
220
- rewriteRunDirectoryPathValueAgainstRewrites(path, rewrites),
221
- );
222
- }
217
+ // #1165: summons.attachmentPaths are caller paths — do not rewrite.
223
218
  }
224
219
 
225
220
  /** Project one admitted page in memory after its containing run moved. */
@@ -229,13 +224,7 @@ export function rewriteAdmittedRoleRunPage(
229
224
  ): void {
230
225
  rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_FIELDS, rewrites);
231
226
  rewriteSourceRunLocator(page.sourceRun, rewrites);
232
- if (Array.isArray(page.attachments)) {
233
- for (const attachment of page.attachments) {
234
- if (isRecord(attachment)) {
235
- rewriteRunDirectoryPathFieldsAgainstRewrites(attachment, ["frozenPath"], rewrites);
236
- }
237
- }
238
- }
227
+ // #1165: admitted attachments are caller paths outside the run directory — do not rewrite.
239
228
  if (isRecord(page.principal)) {
240
229
  rewriteRunDirectoryPathFieldsAgainstRewrites(
241
230
  page.principal,
@@ -432,12 +421,13 @@ async function rewriteNestedMachinePathPages(
432
421
  }
433
422
 
434
423
  /**
435
- * Rewrite the admitted / invocation / runState fact rows (path fields: attachment
436
- * frozenPath / summons.attachmentPaths pointers only), then nested package-owned
437
- * session seams. Callers may rewrite before or after the filesystem move/copy:
438
- * `pagesDirectory` is where the pages currently live on disk; path strings that
439
- * still name `oldRunDirectory` become `newRunDirectory`. `crossRunRewrites`
440
- * covers officer/parent pointers that landed under a different final placement.
424
+ * Rewrite the admitted / invocation / runState fact rows (typed run placement
425
+ * paths only; caller --attach / --request-manifest paths stay as-is, #1165),
426
+ * then nested package-owned session seams. Callers may rewrite before or after
427
+ * the filesystem move/copy: `pagesDirectory` is where the pages currently live
428
+ * on disk; path strings that still name `oldRunDirectory` become
429
+ * `newRunDirectory`. `crossRunRewrites` covers officer/parent pointers that
430
+ * landed under a different final placement.
441
431
  */
442
432
  export async function rewriteRoleRunDurablePages(input: {
443
433
  readonly pagesDirectory: string;
@@ -462,7 +452,7 @@ export async function rewriteRoleRunDurablePages(input: {
462
452
  rewrites,
463
453
  );
464
454
  }
465
- // Open court summons: source-run locators + frozen attachment path pointers.
455
+ // Open court summons: source-run locators only; caller attach paths stay (#1165).
466
456
  if (isRecord(page.currentCourt)) {
467
457
  rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
468
458
  }
@@ -33,7 +33,10 @@ import {
33
33
  resolveEngineModel,
34
34
  resolveEngineName,
35
35
  } from "./engine-detour.ts";
36
- import { engineSessionMaterialFromOptions } from "./package-resources/engine-material.ts";
36
+ import {
37
+ engineSessionMaterialFromOptions,
38
+ engineSessionReadingMaterial,
39
+ } from "./package-resources/engine-material.ts";
37
40
  import { registerEngineDetourTool } from "./engine-detour-tool.ts";
38
41
  import {
39
42
  createReceiptDeliveryPolicy,
@@ -114,7 +117,15 @@ import {
114
117
  resolveLifecycleInvocationPrincipal,
115
118
  } from "./navigator-invocation-identity.ts";
116
119
  import { NAVIGATOR_POST_ROLE_GRACE_MS, raceNavigatorGrace } from "./public-cli/settlement.ts";
117
- import { PACKAGED_ROLE_REGISTRY, isOfficerReviewSeat, packagedRoleActivationFlags, packagedRoleInputFlag, packagedRoleMetadata, packagedRoleOutputTool, packagedRolePhaseFlag, type PackagedRole } from "./packaged-role-registry.ts";
120
+ import {
121
+ PACKAGED_ROLE_REGISTRY,
122
+ packagedRoleActivationFlags,
123
+ packagedRoleInputFlag,
124
+ packagedRoleMetadata,
125
+ packagedRoleOutputTool,
126
+ packagedRolePhaseFlag,
127
+ type PackagedRole,
128
+ } from "./packaged-role-registry.ts";
118
129
  import {
119
130
  createJudgeRoleRuntime,
120
131
  } from "./judge-role.ts";
@@ -1198,12 +1209,9 @@ export function createRoleRuntimeExtension(
1198
1209
  };
1199
1210
  }
1200
1211
  });
1201
- // #879: engine coordinates ride readingMaterial only when station-child
1202
- // officer dialogue replaced the ordinary transport prompt (no double fold).
1212
+ // #1167: engine / outsourcing coordinates ride startup readingMaterial for
1213
+ // every seat (handbook bodies). Transport prompt stays dispatch-only.
1203
1214
  roleHost.on("before_agent_start", () => {
1204
- const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
1205
- if (typeof role !== "string" || !isOfficerReviewSeat(role)) return;
1206
- if (roleHost.getFlag(STATION_CHILD_FLAG.name) !== true) return;
1207
1215
  const engine = resolveEngineName((name) => roleHost.getFlag(name));
1208
1216
  if (engine === undefined || dependencies.packageRoot === undefined) return;
1209
1217
  const engineModel = resolveEngineModel((name) => roleHost.getFlag(name));
@@ -1212,15 +1220,9 @@ export function createRoleRuntimeExtension(
1212
1220
  ...(engineModel === undefined ? {} : { engineModel }),
1213
1221
  packageRoot: dependencies.packageRoot,
1214
1222
  });
1215
- if (material === undefined) return;
1216
- return {
1217
- readingMaterial: {
1218
- kind: "engine-session-material" as const,
1219
- name: material.name,
1220
- ...(material.model === undefined ? {} : { model: material.model }),
1221
- ...(material.materialPath === undefined ? {} : { materialPath: material.materialPath }),
1222
- },
1223
- };
1223
+ const reading = engineSessionReadingMaterial(material);
1224
+ if (reading === undefined) return;
1225
+ return { readingMaterial: reading };
1224
1226
  });
1225
1227
  roleHost.on("before_agent_start", () => {
1226
1228
  const path = roleHost.getFlag(INSPECTOR_SOURCE_RUN_FLAG.name);