@akagilnc/pi-workflow-roles 0.1.5845 → 0.1.5855

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 (66) hide show
  1. package/README.md +4 -4
  2. package/README.zh-CN.md +4 -4
  3. package/dist/acp-host/production-host.js +348 -1254
  4. package/dist/acp-host/role-turn-host.js +4 -98
  5. package/dist/headless-host/production-host.js +15731 -16582
  6. package/dist/headless-host/role-turn-host.js +6 -31
  7. package/dist/migrate-book-topology.js +31 -16
  8. package/dist/navigator-attendance.js +54 -404
  9. package/dist/navigator-invocation-identity.js +0 -2
  10. package/dist/navigator-lookup-host.js +41 -0
  11. package/dist/navigator-lookup.js +68 -0
  12. package/dist/navigator-route-table.js +42 -0
  13. package/dist/package-contracts/navigator-output.js +3 -11
  14. package/dist/packaged-role-registry.js +3 -27
  15. package/dist/public-cli/instruction-seat-run.js +4 -1
  16. package/dist/public-cli/invocation.js +13 -26
  17. package/dist/public-cli/main.js +286 -114
  18. package/dist/public-cli/option-definitions.js +24 -4
  19. package/dist/public-cli/post-admission.js +0 -9
  20. package/dist/public-cli/role-seat-runtime.js +14 -0
  21. package/dist/public-cli/settlement.js +14 -40
  22. package/dist/public-cli/terminal.js +1 -8
  23. package/dist/public-cli/turn-request.js +0 -3
  24. package/dist/public-role-summons.js +0 -1
  25. package/dist/receipt-delivery-policy.js +0 -23
  26. package/dist/role-runtime-dependencies.js +4 -11
  27. package/dist/role-runtime.js +18 -194
  28. package/dist/submission-ledger.js +19 -15
  29. package/dist/ticket-progress.js +23 -5
  30. package/extensions/role-runtime.ts +0 -16
  31. package/package.json +1 -1
  32. package/scripts/build-package.mjs +3 -7
  33. package/src/acp-host/role-turn-host.ts +8 -97
  34. package/src/headless-host/description.ts +0 -2
  35. package/src/headless-host/role-turn-host.ts +7 -32
  36. package/src/host-contracts.ts +5 -7
  37. package/src/navigator-attendance.ts +86 -549
  38. package/src/navigator-invocation-identity.ts +0 -2
  39. package/src/navigator-lookup-host.ts +45 -0
  40. package/src/navigator-lookup.ts +98 -0
  41. package/src/navigator-route-table.ts +92 -0
  42. package/src/package-contracts/navigator-output.ts +4 -15
  43. package/src/packaged-role-registry.ts +3 -32
  44. package/src/public-cli/instruction-seat-run.ts +3 -0
  45. package/src/public-cli/invocation.ts +18 -30
  46. package/src/public-cli/option-definitions.ts +25 -4
  47. package/src/public-cli/post-admission.ts +0 -11
  48. package/src/public-cli/role-seat-runtime.ts +14 -0
  49. package/src/public-cli/settlement.ts +23 -51
  50. package/src/public-cli/terminal.ts +3 -18
  51. package/src/public-cli/turn-request.ts +0 -5
  52. package/src/public-role-summons.ts +0 -8
  53. package/src/receipt-delivery-policy.ts +0 -21
  54. package/src/role-runtime-dependencies.ts +4 -11
  55. package/src/role-runtime.ts +19 -210
  56. package/src/submission-ledger.ts +23 -16
  57. package/src/ticket-progress.ts +32 -5
  58. package/dist/navigator-public-session.js +0 -205
  59. package/dist/navigator-role.js +0 -6
  60. package/dist/navigator-session-contracts.js +0 -227
  61. package/dist/navigator-work-context.js +0 -72
  62. package/resources/navigator-route-playbook.md +0 -33
  63. package/src/navigator-public-session.ts +0 -305
  64. package/src/navigator-role.ts +0 -15
  65. package/src/navigator-session-contracts.ts +0 -320
  66. package/src/navigator-work-context.ts +0 -97
@@ -21,10 +21,6 @@ import {
21
21
  copyAndRecordHostDossier,
22
22
  recordNativeSessionPointer,
23
23
  } from "../host-session-record.ts";
24
- import {
25
- NAVIGATOR_OUTPUT_TOOL_NAME,
26
- navigatorProseFromUnknown,
27
- } from "../package-contracts/navigator-output.ts";
28
24
  import {
29
25
  renderSystemPromptOverride,
30
26
  resolveBoundHostSessionId,
@@ -33,54 +29,6 @@ import {
33
29
  } from "../prepared-role-turn.ts";
34
30
  import { acpModelId, type AcpHostDescription } from "./description.ts";
35
31
 
36
- import { isRecord } from "../unknown-value.ts";
37
-
38
- /**
39
- * #959: collect free-form agent text from ACP session/update stream.
40
- * Used only when the navigator seat spoke prose without calling the output tool.
41
- * ACP agent speech is only agent_message / agent_message_chunk — never user,
42
- * thought, or other *_message kinds (load replay must not poison the bucket).
43
- *
44
- * Standard ACP nests under params.update: { sessionUpdate, content }.
45
- * Flat params.sessionUpdate / string params.update remain accepted for host variants.
46
- */
47
- function acpAgentTextChunk(params: Readonly<Record<string, unknown>>): string | undefined {
48
- let kind: unknown;
49
- let content: unknown;
50
- let textFallback: unknown;
51
-
52
- const nested = params.update;
53
- if (isRecord(nested)) {
54
- const record = nested as Record<string, unknown>;
55
- kind = record.sessionUpdate;
56
- content = record.content;
57
- textFallback = record.text;
58
- } else {
59
- kind = params.sessionUpdate ?? nested;
60
- content = params.content;
61
- textFallback = params.text;
62
- }
63
-
64
- if (kind !== "agent_message_chunk" && kind !== "agent_message") return undefined;
65
- if (typeof content === "string" && content.length > 0) return content;
66
- if (isRecord(content)) {
67
- const record = content as Record<string, unknown>;
68
- if (typeof record.text === "string" && record.text.length > 0) return record.text;
69
- }
70
- if (Array.isArray(content)) {
71
- const parts: string[] = [];
72
- for (const part of content) {
73
- if (typeof part === "string" && part.length > 0) parts.push(part);
74
- else if (typeof part === "object" && part !== null) {
75
- const record = part as Record<string, unknown>;
76
- if (typeof record.text === "string" && record.text.length > 0) parts.push(record.text);
77
- }
78
- }
79
- if (parts.length > 0) return parts.join("");
80
- }
81
- if (typeof textFallback === "string" && textFallback.length > 0) return textFallback;
82
- return undefined;
83
- }
84
32
 
85
33
  /** ACP v1 surface used by the generic ACP adapter. Protocol details stay in this module. */
86
34
  export interface AcpConnection {
@@ -279,20 +227,6 @@ export function createAcpRoleTurnHost(config: AcpRoleTurnHostConfig): RoleTurnHo
279
227
  params: Readonly<Record<string, unknown>>,
280
228
  ): Promise<Readonly<Record<string, unknown>>> => connection!.request(method, params);
281
229
 
282
- // #959: navigator free-form agent text — only while session/prompt is in flight.
283
- // session/load replays history via session/update; those must not enter the bucket
284
- // (resume / set_model load would otherwise prepend prior turns as "this turn" prose).
285
- const agentProseChunks: string[] = [];
286
- let collectAgentProse = false;
287
- connection.onNotification?.((method, params) => {
288
- const isSessionUpdate = method === "session/update";
289
- if (!isSessionUpdate) return;
290
- if (collectAgentProse) {
291
- const chunk = acpAgentTextChunk(params);
292
- if (chunk !== undefined) agentProseChunks.push(chunk);
293
- }
294
- });
295
-
296
230
  const initialized = await rpc("initialize", {
297
231
  protocolVersion: 1,
298
232
  clientCapabilities: {},
@@ -387,26 +321,15 @@ export function createAcpRoleTurnHost(config: AcpRoleTurnHostConfig): RoleTurnHo
387
321
  outputSchema: deliveredSchema,
388
322
  }, "acp-host");
389
323
  let result: Readonly<Record<string, unknown>>;
390
- // Open the prose gate only for this prompt round; clear any stale chunks first.
391
- agentProseChunks.length = 0;
392
- collectAgentProse = prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME;
393
- try {
394
- result = await raceAgainstHostAbort(
395
- activeConnection.request("session/prompt", {
396
- sessionId: activeSessionId,
397
- prompt: [{ type: "text", text: prompt }],
398
- }),
399
- abortSignal,
400
- "ACP host aborted",
401
- );
402
- } catch (error) {
403
- collectAgentProse = false;
404
- agentProseChunks.length = 0;
405
- throw error;
406
- }
407
- collectAgentProse = false;
324
+ result = await raceAgainstHostAbort(
325
+ activeConnection.request("session/prompt", {
326
+ sessionId: activeSessionId,
327
+ prompt: [{ type: "text", text: prompt }],
328
+ }),
329
+ abortSignal,
330
+ "ACP host aborted",
331
+ );
408
332
  if (result.stopReason === "refusal") {
409
- agentProseChunks.length = 0;
410
333
  reportedFailure = { diagnostic: result.stopReason, details: result };
411
334
  return {
412
335
  status: "terminal",
@@ -418,18 +341,6 @@ export function createAcpRoleTurnHost(config: AcpRoleTurnHostConfig): RoleTurnHo
418
341
  },
419
342
  };
420
343
  }
421
- // #959: navigator prose exit when the model spoke without the output tool.
422
- // Tool path still wins via MCP; ingest is a no-op once the tool already sealed.
423
- // Emptiness via shared projector; payload keeps original bytes (LLM 原话过手).
424
- if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME) {
425
- const prose = agentProseChunks.join("");
426
- agentProseChunks.length = 0;
427
- if (navigatorProseFromUnknown(prose) !== undefined) {
428
- await prepared.ingestStructuredOutput({ prose });
429
- }
430
- } else {
431
- agentProseChunks.length = 0;
432
- }
433
344
  return { status: "delivered", stderr: activeConnection.stderr?.() ?? "" };
434
345
  },
435
346
  async afterAccepted() {
@@ -433,8 +433,6 @@ export function codexTurnArgs(options: {
433
433
  /**
434
434
  * Absolute path for the native `--output-schema` flag.
435
435
  * File holds the Codex-strict transport projection of the open declaration (#1148).
436
- * Optional: omit for direct navigator prose exit (#959); attendance byStatus
437
- * prepare mounts it via RoleTurnRequest.navigatorByStatusPrepare (#1160).
438
436
  */
439
437
  readonly outputSchemaPath?: string;
440
438
  readonly mcpServers: readonly Readonly<Record<string, unknown>>[];
@@ -46,7 +46,6 @@ import {
46
46
  isCodexExecDescription,
47
47
  type HeadlessHostDescription,
48
48
  } from "./description.ts";
49
- import { NAVIGATOR_OUTPUT_TOOL_NAME } from "../package-contracts/navigator-output.ts";
50
49
 
51
50
  import { errorText, isRecord } from "../unknown-value.ts";
52
51
 
@@ -392,7 +391,7 @@ function terminalFromSpawned(
392
391
  function buildTurnArgs(options: {
393
392
  readonly description: HeadlessHostDescription;
394
393
  readonly systemPromptPath: string;
395
- /** Open schema for Claude --json-schema; omit for #959 navigator prose-exit seats. */
394
+ /** Open schema for Claude --json-schema. */
396
395
  readonly jsonSchema?: Readonly<Record<string, unknown>>;
397
396
  readonly mcpServers: readonly Readonly<Record<string, unknown>>[];
398
397
  readonly mcpConfigPath?: string;
@@ -408,7 +407,6 @@ function buildTurnArgs(options: {
408
407
  if (options.sessionKind === "resume" && !options.sessionId) {
409
408
  throw new Error("codex resume requires a bound thread_id");
410
409
  }
411
- // Codex always mounts --output-schema when the path is supplied (incl. navigator byStatus #1160).
412
410
  return codexTurnArgs({
413
411
  systemPromptPath: options.systemPromptPath,
414
412
  ...(options.outputSchemaPath === undefined ? {} : { outputSchemaPath: options.outputSchemaPath }),
@@ -429,7 +427,6 @@ function buildTurnArgs(options: {
429
427
  return headlessTurnArgs({
430
428
  description: options.description,
431
429
  systemPromptPath: options.systemPromptPath,
432
- // #959: navigator omits --json-schema so free-form prose is a lawful exit.
433
430
  ...(options.jsonSchema === undefined ? {} : { jsonSchema: options.jsonSchema }),
434
431
  mcpConfigPath: options.mcpConfigPath,
435
432
  ...(options.model === undefined ? {} : { model: options.model }),
@@ -444,11 +441,6 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
444
441
  const prepared = await config.prepare(request);
445
442
  const systemPrompt = renderSystemPromptOverride(prepared.systemPrompt);
446
443
  const codex = isCodexExecDescription(config.description);
447
- // #1160: one exit-mode decision per turn — direct navigator free prose vs structured.
448
- // Attendance sets request.navigatorByStatusPrepare; direct ak-role navigator does not.
449
- const navigatorProseExit =
450
- prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME
451
- && request.navigatorByStatusPrepare !== true;
452
444
  let outcome: RoleTurnResult = failure("session", "HeadlessNoOutcome", "no-outcome");
453
445
  try {
454
446
  // Claude mints a package UUID for --session-id; codex waits for thread.started.
@@ -490,11 +482,9 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
490
482
  if (codex) {
491
483
  // #1148: Codex --output-schema requires a native strict transport schema.
492
484
  // Project from the unique open declaration; do not alter package receipt rules.
493
- if (!navigatorProseExit) {
494
- outputSchemaPath = join(inputsDirectory, "output-schema.json");
495
- deliveredSchema = closeJsonSchemaForCodex(prepared.jsonSchema);
496
- await writeFile(outputSchemaPath, `${JSON.stringify(deliveredSchema, null, 2)}\n`, "utf8");
497
- }
485
+ outputSchemaPath = join(inputsDirectory, "output-schema.json");
486
+ deliveredSchema = closeJsonSchemaForCodex(prepared.jsonSchema);
487
+ await writeFile(outputSchemaPath, `${JSON.stringify(deliveredSchema, null, 2)}\n`, "utf8");
498
488
  } else {
499
489
  mcpConfigPath = join(inputsDirectory, "mcp-config.json");
500
490
  await writeFile(
@@ -502,7 +492,7 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
502
492
  `${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}\n`,
503
493
  "utf8",
504
494
  );
505
- if (!navigatorProseExit) deliveredSchema = prepared.jsonSchema;
495
+ deliveredSchema = prepared.jsonSchema;
506
496
  }
507
497
  startedWithSchema = deliveredSchema;
508
498
  } catch (setupError) {
@@ -530,8 +520,7 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
530
520
  args = buildTurnArgs({
531
521
  description: config.description,
532
522
  systemPromptPath,
533
- // Direct navigator prose exit omits --json-schema; byStatus prepare mounts it.
534
- ...(navigatorProseExit ? {} : { jsonSchema: prepared.jsonSchema }),
523
+ jsonSchema: prepared.jsonSchema,
535
524
  mcpServers: prepared.mcpServers,
536
525
  ...(mcpConfigPath === undefined ? {} : { mcpConfigPath }),
537
526
  ...(outputSchemaPath === undefined ? {} : { outputSchemaPath }),
@@ -669,13 +658,7 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
669
658
 
670
659
  const deliverReply = async (): Promise<ReturnType<typeof deliveredFromSpawned> | undefined> => {
671
660
  if (!observation.turnCompleted || observation.finalMessage === undefined) return undefined;
672
- if (navigatorProseExit) {
673
- // Direct ak-role navigator: free-form agent_message is the prose body.
674
- if (observation.finalMessage.trim() === "") return undefined;
675
- await prepared.ingestStructuredOutput({ prose: observation.finalMessage });
676
- return deliveredFromSpawned(spawned);
677
- }
678
- // Structured seats (incl. #1160 byStatus prepare): native JSON receipt.
661
+ // Native JSON receipt.
679
662
  let receipt: unknown;
680
663
  try {
681
664
  receipt = JSON.parse(observation.finalMessage);
@@ -723,14 +706,6 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
723
706
 
724
707
  if (envelope.structured_output !== undefined) {
725
708
  await prepared.ingestStructuredOutput(envelope.structured_output);
726
- } else if (
727
- navigatorProseExit
728
- && typeof envelope.result === "string"
729
- && envelope.result.trim() !== ""
730
- ) {
731
- // #959: direct navigator prose exit — free-form result text is the body
732
- // when structured_output is absent (json-schema omitted).
733
- await prepared.ingestStructuredOutput({ prose: envelope.result });
734
709
  }
735
710
  return deliveredFromSpawned(spawned);
736
711
  } catch (error) {
@@ -134,7 +134,11 @@ export type RoleTurnActivation =
134
134
  }
135
135
  | { readonly role: "inspector"; readonly sourceRun?: string }
136
136
  | { readonly role: "gatekeeper" }
137
- | { readonly role: "navigator" }
137
+ | {
138
+ readonly role: "navigator";
139
+ /** Structured target seat for the lookup run (#1192); absent = whole table. */
140
+ readonly forRole?: string;
141
+ }
138
142
  | { readonly role: "auditor" }
139
143
  | { readonly role: "diarist" }
140
144
  | { readonly role: "secretariat" };
@@ -199,12 +203,6 @@ export type RoleTurnRequest = {
199
203
  readonly host?: string;
200
204
  /** Station child role run (#840): omit automatic navigator attendance. */
201
205
  readonly stationChild?: boolean;
202
- /**
203
- * #1160 attendance auto-prepare: host mounts native structured schema so
204
- * byStatus returns as structured fields. Direct `ak-role navigator` omits
205
- * this and keeps the free-form prose exit (#959).
206
- */
207
- readonly navigatorByStatusPrepare?: boolean;
208
206
  /**
209
207
  * #1132: the effective delivery-request ceiling resolved once by the caller
210
208
  * from the single configured `autoResumeLimit` value and projected here, so