@akagilnc/pi-workflow-roles 0.1.6017 → 0.1.6021

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.
@@ -684,31 +684,13 @@ export async function dispatchPostAdmissionTurn(input) {
684
684
  pendingTerminal !== undefined &&
685
685
  result.terminal === pendingTerminal) {
686
686
  try {
687
- // #1171 F2-R2 / F2-R3 (#419) / F2-R5: only the soft-reask turn itself
688
- // preserves the sealed terminal face. ticketReasksSpent is budget across
689
- // rounds — after audit continue, ordinary no-volume turns publish
690
- // no_receipt honestly. previewOnly skips the terminal pointer;
691
- // recordAttemptHistory still appends.
692
- const softTicketReaskNoSeal = pendingSettlement !== "sealed" && env.softTicketReaskTurn === true;
693
- const noSealScope = softTicketReaskNoSeal
694
- ? {
695
- ...courtScope,
696
- previewOnly: true,
697
- recordAttemptHistory: true,
698
- }
699
- : { ...courtScope, recordAttemptHistory: true };
687
+ const noSealScope = { ...courtScope, recordAttemptHistory: true };
700
688
  const terminal = pendingSettlement === "sealed"
701
689
  ? await adapters.trySettle(admitted, env.principalAuthority, { ...courtScope, recordAttemptHistory: true })
702
690
  : await attachRecordedSubmissions(admitted, await settleHostEndedNoReceipt(admitted, env.principalAuthority, noSealScope, receiptDelivery.issuedDeliveryRequests()), noSealScope);
703
691
  if (terminal === undefined)
704
692
  throw new Error("settled host attempt vanished before publication");
705
693
  result = { ...result, terminal, exitCode: exitCodeForTerminalOutcome(terminal.roleOutcome) };
706
- // #1171 F2-R7: ownership evidence at this soft-reask turn's seal —
707
- // mutate the live ownership cell carried on env (survives spreads).
708
- if (pendingSettlement === "sealed" && env.softTicketReaskTurn === true
709
- && env.softTicketReaskOwnership !== undefined) {
710
- env.softTicketReaskOwnership.sealedSubstitute = true;
711
- }
712
694
  if (pendingSettlement === "sealed" && terminal.roleOutcome.kind === "accepted"
713
695
  && request.courtAttemptId !== undefined && request.courtAttemptId.length > 0) {
714
696
  try {
@@ -20,8 +20,7 @@ const reportTicketArgsSchema = Type.Object({
20
20
  }),
21
21
  }, { additionalProperties: true });
22
22
  export const REPORT_TICKET_TOOL_DESCRIPTION = "向包申报本票号。已知票号时开工第一件事调用;包当场把本腿归到票号目录。"
23
- + "尚无票号(例如中书省建票前)不要调用,取得后再报。"
24
- + "交卷时若仍未报过且交卷亦未带票号,包会经既有重交通道再问一次。";
23
+ + "尚无票号(例如中书省建票前)不要调用,取得后再报。";
25
24
  function pageString(page, key) {
26
25
  const value = page?.[key];
27
26
  return typeof value === "string" && value.trim() !== "" ? value : undefined;
@@ -153,5 +152,3 @@ export function registerReportTicketTool(roleHost, hostActions) {
153
152
  },
154
153
  });
155
154
  }
156
- /** Soft re-ask when a sealed submission still leaves the leg unbound (#1171 / ADR 0073). */
157
- export const MISSING_TICKET_REASK_MATERIAL = "resources/missing-ticket-reask.md";
@@ -1,4 +1,5 @@
1
- import { sessionFileIn, sessionFileOf } from "./role-run-placement.js";
1
+ import { isUnboundRunDirectory, sessionFileIn, sessionFileOf } from "./role-run-placement.js";
2
+ import { readPackageMaterial } from "./session-opening-materials.js";
2
3
  import { resolveActivationLedgerHome, tryHomeFromAkRolesPath, } from "./activation-ledger-topology.js";
3
4
  import { courtAttemptIdFromHostContext, runDirectoryFromHostContext, } from "./host-contracts.js";
4
5
  import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
@@ -491,6 +492,20 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
491
492
  ? { lens: rawLens }
492
493
  : {}),
493
494
  });
495
+ // Native structured-output hosts have no tool-result reply to the model.
496
+ // Keep the conversation open only after the receipt is durably sealed.
497
+ const runDirectory = runDirectoryFromHostContext(context);
498
+ if (context.host !== "claude" && context.host !== "codex"
499
+ && runDirectory !== undefined && isUnboundRunDirectory(runDirectory)) {
500
+ result = {
501
+ ...result,
502
+ terminate: false,
503
+ content: [...result.content, {
504
+ type: "text",
505
+ text: (await readPackageMaterial("resources/ticket-at-receipt.md")).trim(),
506
+ }],
507
+ };
508
+ }
494
509
  }
495
510
  catch (error) {
496
511
  if (toolThrew)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.6017",
3
+ "version": "0.1.6021",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1 @@
1
+ 卷已收下,不用重交。本腿还没有票号:知道就调 ak_report_ticket 报上;不知道就直接结束。
@@ -4,10 +4,7 @@
4
4
  * starts two ordinary single-axis runs here.
5
5
  */
6
6
  import { dirname, resolve } from "node:path";
7
- import { MISSING_TICKET_REASK_MATERIAL } from "../report-ticket-tool.ts";
8
7
  import { isUnboundRunDirectory, sessionFileOf } from "../role-run-placement.ts";
9
- import { rewriteRunDirectoryPathValue } from "../role-run-relocation.ts";
10
- import { readPackageMaterial } from "../session-opening-materials.ts";
11
8
  import { createPiDoctorAuditor } from "../doctor-auditor.ts";
12
9
 
13
10
  import type { DurablePrincipalAuthority, HostContext, RoleTurnRequest } from "../host-contracts.ts";
@@ -193,21 +190,10 @@ function unreadablePostSubmissionStatus(
193
190
  * status: the caller presents the volumes already in hand and does not advance
194
191
  * review. ADR 0007 audit continues are not this shape.
195
192
  */
196
- /**
197
- * Drop turn-scoped soft-reask identity; keep cross-turn budgets and ownership cell.
198
- * #1171 F2-R5 / F2-R9: ordinary status reask and court continue must not inherit
199
- * softTicketReaskTurn (that flag only governs the soft-reask turn's own settle).
200
- */
201
- function withoutSoftTicketReaskTurn(env: InstructionSeatRunEnv): InstructionSeatRunEnv {
202
- const { softTicketReaskTurn: _softTicketReaskTurn, ...rest } = env;
203
- return rest;
204
- }
205
-
206
193
  function withUnreadableReask(env: InstructionSeatRunEnv): InstructionSeatRunEnv | undefined {
207
194
  const spent = env.unreadableReasksSpent ?? 0;
208
195
  if (spent >= deliveryLimitFromConfig(env.autoResumeLimit)) return undefined;
209
- // Ordinary status reask: strip soft-reask turn identity; keep spent budget (#1171 F2-R9).
210
- return { ...withoutSoftTicketReaskTurn(env), unreadableReasksSpent: spent + 1 };
196
+ return { ...env, unreadableReasksSpent: spent + 1 };
211
197
  }
212
198
 
213
199
  /** Budget spent on an unreadable status. Distinct from "status is readable". */
@@ -406,144 +392,12 @@ async function reaskUnreadablePostSubmissionStatus(
406
392
  );
407
393
  }
408
394
 
409
- /**
410
- * Soft-reask call outcome at the missing-ticket seam (#1171 F2-R6 / F2-R7).
411
- * Ownership is decided here once from this nested chain's settlement evidence
412
- * (soft-reask turn sealed → ownership cell; or returned terminal still carries volume);
413
- * callers must not re-judge the same criterion.
414
- */
415
- type SoftTicketReaskOutcome =
416
- | { readonly kind: "none" }
417
- | { readonly kind: "nested_owns"; readonly result: SeatRunResult }
418
- | { readonly kind: "no_substitute"; readonly result: SeatRunResult };
419
-
420
- /**
421
- * #1171: sealed submission still leaves the leg unbound → soft reask once.
422
- * Does not reject the sealed receipt; exhaustion leaves unbound as filed.
423
- * Reask copy lives in package resources (ADR 0073).
424
- * #1171 F2-R7: ownership comes from this nested resume's settlement seam
425
- * (softTicketReaskOwnership.sealedSubstitute set when the soft-reask turn itself seals),
426
- * not full-leg sealed count / time-window deltas that can absorb another court's seal.
427
- */
428
- async function reaskMissingTicketOnce(
429
- admitted: AdmittedRoleInvocation,
430
- terminal: TerminalResult | undefined,
431
- env: InstructionSeatRunEnv,
432
- io: CliIo,
433
- ): Promise<SoftTicketReaskOutcome> {
434
- if ((env.ticketReasksSpent ?? 0) >= 1) return { kind: "none" };
435
- // #1192: a table lookup has no one to ask, and a second turn would re-seal.
436
- if (isNavigatorSeat(admitted.role)) return { kind: "none" };
437
- if (admitted.ticketNumber !== undefined) return { kind: "none" };
438
- if (!isUnboundRunDirectory(admitted.runDirectory)) return { kind: "none" };
439
- if (terminal?.roleOutcome.kind !== "accepted" && terminal?.roleOutcome.kind !== "audit_escalation") {
440
- return { kind: "none" };
441
- }
442
- const payloads = terminal.roleOutcome.payloads ?? [];
443
- if (payloads.length === 0) return { kind: "none" };
444
- // Sealed-with-ticket skips via admitted.ticketNumber after bindSealedTicketNumber
445
- // (post-admission). Do not re-parse payload.ticketNumber here — that would
446
- // duplicate the existing ticket seam (#1171 notary: no rule copy).
447
- const instruction = (await readPackageMaterial(MISSING_TICKET_REASK_MATERIAL)).trim();
448
- // Spend budget and mark this turn as the soft reask (settlement identity).
449
- // Ownership cell is set at that turn's settlement; env spreads keep the same
450
- // ref through audit continue — see envForCourtContinue (#1171 F2-R5 / F2-R7).
451
- const softTicketReaskOwnership = { sealedSubstitute: false };
452
- const softReaskEnv: InstructionSeatRunEnv = {
453
- ...env,
454
- ticketReasksSpent: 1,
455
- softTicketReaskTurn: true,
456
- softTicketReaskOwnership,
457
- };
458
- // Named #1171 missing-ticket: summons opens a new court; message carries the
459
- // package reask copy (not arbitrary summons.instruction passthrough).
460
- const result = await runPublicInstructionSeatResume(
461
- {
462
- runId: admitted.runId,
463
- runDirectory: admitted.runDirectory,
464
- message: instruction,
465
- summons: { instructionEmpty: true },
466
- },
467
- softReaskEnv,
468
- io,
469
- );
470
- if (
471
- softTicketReaskOwnership.sealedSubstitute
472
- || terminalCarriesSealedSubmission(result.terminal)
473
- ) {
474
- return { kind: "nested_owns", result };
475
- }
476
- return { kind: "no_substitute", result };
477
- }
478
-
479
- /** Court continue: keep cross-turn budgets + ownership cell; drop turn-scoped soft-reask identity. */
395
+ /** Court continue resets the unreadable-status budget. */
480
396
  function envForCourtContinue(env: InstructionSeatRunEnv): InstructionSeatRunEnv {
481
- return { ...withoutSoftTicketReaskTurn(env), unreadableReasksSpent: 0 };
482
- }
483
-
484
- /** True when a terminal still carries a sealed accepted / audit_escalation volume. */
485
- function terminalCarriesSealedSubmission(terminal: TerminalResult | undefined): boolean {
486
- const kind = terminal?.roleOutcome.kind;
487
- if (kind !== "accepted" && kind !== "audit_escalation") return false;
488
- return (terminal?.roleOutcome.payloads ?? []).length > 0;
489
- }
490
-
491
- /**
492
- * #1171 F2-R2: kept original terminal may still name pre-relocate artifact
493
- * paths after a report-only reask moved the leg. Project onto live admitted
494
- * via the same rewrite seam post-admission uses after relocate.
495
- */
496
- function projectKeptOriginalArtifactsOntoLiveAdmitted(
497
- original: SeatRunResult,
498
- kept: SeatRunResult,
499
- ): void {
500
- const oldRunDirectory = original.admitted?.runDirectory;
501
- const newRunDirectory = kept.admitted?.runDirectory;
502
- if (
503
- oldRunDirectory === undefined
504
- || newRunDirectory === undefined
505
- || oldRunDirectory === newRunDirectory
506
- || kept.terminal === undefined
507
- ) {
508
- return;
509
- }
510
- for (const artifact of kept.terminal.artifacts) {
511
- artifact.path = rewriteRunDirectoryPathValue(
512
- artifact.path,
513
- oldRunDirectory,
514
- newRunDirectory,
515
- ) as string;
516
- }
397
+ return { ...env, unreadableReasksSpent: 0 };
517
398
  }
518
399
 
519
- /**
520
- * #1171 F2: missing-ticket reask did not seal a substitute — keep original
521
- * terminal; take live placement from the reask when it relocated.
522
- * #1171 F2-R1: silence / report-only stays on the original chain; a real host
523
- * failure (nonzero exit) must be delivered honestly — do not wash it into the
524
- * original accepted result. Sealed original volume remains on disk either way.
525
- * #1171 F2-R2: after keep, project report artifact paths onto the live
526
- * admitted directory so public result, durable face, and artifact refs agree.
527
- * Substitute ownership is decided once at the soft-reask call seam (F2-R6);
528
- * this helper only finishes the keep path.
529
- */
530
- function mergeMissingTicketReaskKeepOriginal(
531
- original: SeatRunResult,
532
- ticketReask: SeatRunResult,
533
- ): SeatRunResult {
534
- if (ticketReask.exitCode !== 0) return ticketReask;
535
- const admitted = ticketReask.admitted ?? original.admitted;
536
- if (admitted === undefined) return { ...original };
537
- const kept = { ...original, admitted };
538
- projectKeptOriginalArtifactsOntoLiveAdmitted(original, kept);
539
- return kept;
540
- }
541
-
542
- /**
543
- * Post-submission status reask, then missing-ticket soft reask, then audit.
544
- * #1171 F3: status exhaustion must not skip the one missing-ticket reask.
545
- * #1171 F2: ticket reask without a substitute seal continues the original chain.
546
- */
400
+ /** Post-submission status reask, then audit. */
547
401
  async function continueAfterPostSubmissionGuards(
548
402
  result: SeatRunResult,
549
403
  admittedRole: PackagedRole,
@@ -562,44 +416,22 @@ async function continueAfterPostSubmissionGuards(
562
416
  env,
563
417
  io,
564
418
  );
565
- let afterStatus = result;
419
+ let continued = result;
566
420
  if (isUnreadableReaskExhausted(unreadableReask)) {
567
421
  const terminal = result.terminal === undefined
568
422
  ? undefined
569
423
  : withUnsettledDirection(result.terminal);
570
- afterStatus = terminal === undefined
424
+ continued = terminal === undefined
571
425
  ? { ...result, admitted: live }
572
426
  : { ...result, admitted: live, terminal };
573
- // Fall through: missing-ticket reask still owed on the original sealed volume.
574
427
  } else if (unreadableReask !== undefined) {
575
428
  return unreadableReask;
576
429
  }
577
- const forTicket = afterStatus.admitted ?? live;
578
- // Ownership is decided once inside reaskMissingTicketOnce (#1171 F2-R6).
579
- const softReask = await reaskMissingTicketOnce(
580
- forTicket,
581
- afterStatus.terminal ?? result.terminal,
582
- env,
583
- io,
584
- );
585
- if (softReask.kind === "nested_owns") {
586
- // Nested resume already finished guards + audit/present for the substitute.
587
- // Do not run a second outer settlement of the same public call (#1171 F2-R4b).
588
- return softReask.result;
589
- }
590
- const continued = softReask.kind === "none"
591
- ? afterStatus
592
- : mergeMissingTicketReaskKeepOriginal(afterStatus, softReask.result);
593
430
  const continuedAdmitted = continued.admitted ?? live;
594
- // Spent budget rides the outer audit/continue chain (#1171 F2-R4a). Soft-reask
595
- // settlement identity does not — ordinary continue turns publish no_receipt (#1171 F2-R5).
596
- const continuedEnv = softReask.kind !== "none"
597
- ? { ...env, ticketReasksSpent: 1 }
598
- : env;
599
431
  if (AUDITED_ROLES.has(admittedRole) && continued.terminal?.roleOutcome.kind === "accepted") {
600
432
  return auditSubmittedRole(
601
433
  { ...continued, admitted: continuedAdmitted },
602
- continuedEnv,
434
+ env,
603
435
  io,
604
436
  );
605
437
  }
@@ -1168,8 +1000,7 @@ export async function runPublicInstructionSeat(
1168
1000
  const result = await runCountersignBody(parsed, env, {
1169
1001
  stdout: (value) => held.push(value), stderr: io.stderr,
1170
1002
  });
1171
- // Same post-submission guards as every other seat (#1171 F8): missing-ticket
1172
- // soft reask once, then audit — no early return that skips the reask.
1003
+ // Apply the same post-submission guards and audit as every other seat.
1173
1004
  return continueAfterPostSubmissionGuards(result, "countersign", env, io, held);
1174
1005
  }
1175
1006
 
@@ -1345,9 +1176,7 @@ export async function runPublicInstructionSeat(
1345
1176
  await persistAdmittedSourceRunPath(admitted, auditorSource, auditorSubject);
1346
1177
  admitted = { ...admitted, sourceRunPath: auditorSource } as AdmittedRoleInvocation;
1347
1178
  }
1348
- // #1208 C2: same helper as resume — known board ticket on the audited
1349
- // source binds and relocates before the missing-ticket soft reask can
1350
- // fire. True no-ticket sources stay unbound (#1171 asks once).
1179
+ // #1208 C2: same helper as resume — inherit the audited source's known ticket.
1351
1180
  admitted = await inheritKnownTicketFromSource(admitted, env.principalAuthority);
1352
1181
 
1353
1182
  const runAdmitted = async (): Promise<SeatRunResult> => {
@@ -1736,8 +1565,6 @@ async function auditSubmittedRole(
1736
1565
  resumedOfficer?: AdmittedRoleInvocation,
1737
1566
  passedReceipt?: unknown,
1738
1567
  ): Promise<SeatRunResult> {
1739
- // Ordinary audit chain: drop soft-reask turn identity; keep budgets/ownership (#1171 F2-R9).
1740
- env = withoutSoftTicketReaskTurn(env);
1741
1568
  const admitted = turn.admitted;
1742
1569
  if (admitted === undefined || !AUDITED_ROLES.has(admitted.role)
1743
1570
  || turn.terminal?.roleOutcome.kind !== "accepted") return turn;
@@ -449,23 +449,6 @@ export type PostAdmissionEnv = {
449
449
  * keeps this env's autoResumeLimit; the counter is the only thing that moves.
450
450
  */
451
451
  unreadableReasksSpent?: number;
452
- /**
453
- * #1171: missing-ticket soft reasks already issued on this chain. Hard ceiling
454
- * is one — still no ticket after that stays unbound with the sealed receipt.
455
- * Budget only across rounds; not the current turn's settlement identity.
456
- */
457
- ticketReasksSpent?: number;
458
- /**
459
- * #1171 F2-R5: this turn is the one soft reask. Keep the sealed terminal face
460
- * when it ends without a substitute seal. Not carried into audit continue.
461
- */
462
- softTicketReaskTurn?: true;
463
- /**
464
- * #1171 F2-R7: live ownership cell for this soft-reask nested chain.
465
- * Created at soft-reask dispatch; settlement of that turn sets sealedSubstitute.
466
- * Shared ref survives env spreads — not a second ledger.
467
- */
468
- softTicketReaskOwnership?: { sealedSubstitute: boolean };
469
452
  createRunId?: () => string;
470
453
  /**
471
454
  * Parent cancellation for a nested public summon (#675). Every dispatched turn
@@ -1220,20 +1203,7 @@ export async function dispatchPostAdmissionTurn<
1220
1203
  result.terminal === pendingTerminal
1221
1204
  ) {
1222
1205
  try {
1223
- // #1171 F2-R2 / F2-R3 (#419) / F2-R5: only the soft-reask turn itself
1224
- // preserves the sealed terminal face. ticketReasksSpent is budget across
1225
- // rounds — after audit continue, ordinary no-volume turns publish
1226
- // no_receipt honestly. previewOnly skips the terminal pointer;
1227
- // recordAttemptHistory still appends.
1228
- const softTicketReaskNoSeal =
1229
- pendingSettlement !== "sealed" && env.softTicketReaskTurn === true;
1230
- const noSealScope = softTicketReaskNoSeal
1231
- ? {
1232
- ...courtScope,
1233
- previewOnly: true as const,
1234
- recordAttemptHistory: true as const,
1235
- }
1236
- : { ...courtScope, recordAttemptHistory: true as const };
1206
+ const noSealScope = { ...courtScope, recordAttemptHistory: true as const };
1237
1207
  const terminal = pendingSettlement === "sealed"
1238
1208
  ? await adapters.trySettle(admitted, env.principalAuthority,
1239
1209
  { ...courtScope, recordAttemptHistory: true })
@@ -1243,12 +1213,6 @@ export async function dispatchPostAdmissionTurn<
1243
1213
  noSealScope);
1244
1214
  if (terminal === undefined) throw new Error("settled host attempt vanished before publication");
1245
1215
  result = { ...result, terminal, exitCode: exitCodeForTerminalOutcome(terminal.roleOutcome) };
1246
- // #1171 F2-R7: ownership evidence at this soft-reask turn's seal —
1247
- // mutate the live ownership cell carried on env (survives spreads).
1248
- if (pendingSettlement === "sealed" && env.softTicketReaskTurn === true
1249
- && env.softTicketReaskOwnership !== undefined) {
1250
- env.softTicketReaskOwnership.sealedSubstitute = true;
1251
- }
1252
1216
  if (pendingSettlement === "sealed" && terminal.roleOutcome.kind === "accepted"
1253
1217
  && request.courtAttemptId !== undefined && request.courtAttemptId.length > 0) {
1254
1218
  try {
@@ -40,8 +40,7 @@ const reportTicketArgsSchema = Type.Object(
40
40
 
41
41
  export const REPORT_TICKET_TOOL_DESCRIPTION =
42
42
  "向包申报本票号。已知票号时开工第一件事调用;包当场把本腿归到票号目录。"
43
- + "尚无票号(例如中书省建票前)不要调用,取得后再报。"
44
- + "交卷时若仍未报过且交卷亦未带票号,包会经既有重交通道再问一次。";
43
+ + "尚无票号(例如中书省建票前)不要调用,取得后再报。";
45
44
 
46
45
  function pageString(page: Record<string, unknown> | undefined, key: string): string | undefined {
47
46
  const value = page?.[key];
@@ -199,6 +198,3 @@ export function registerReportTicketTool(
199
198
  },
200
199
  });
201
200
  }
202
-
203
- /** Soft re-ask when a sealed submission still leaves the leg unbound (#1171 / ADR 0073). */
204
- export const MISSING_TICKET_REASK_MATERIAL = "resources/missing-ticket-reask.md" as const;
@@ -1,4 +1,5 @@
1
- import { sessionFileIn, sessionFileOf } from "./role-run-placement.ts";
1
+ import { isUnboundRunDirectory, sessionFileIn, sessionFileOf } from "./role-run-placement.ts";
2
+ import { readPackageMaterial } from "./session-opening-materials.ts";
2
3
 
3
4
  import {
4
5
  resolveActivationLedgerHome,
@@ -676,6 +677,20 @@ export function createSubmissionLedgerHost(
676
677
  ? { lens: rawLens }
677
678
  : {}),
678
679
  });
680
+ // Native structured-output hosts have no tool-result reply to the model.
681
+ // Keep the conversation open only after the receipt is durably sealed.
682
+ const runDirectory = runDirectoryFromHostContext(context);
683
+ if (context.host !== "claude" && context.host !== "codex"
684
+ && runDirectory !== undefined && isUnboundRunDirectory(runDirectory)) {
685
+ result = {
686
+ ...result,
687
+ terminate: false,
688
+ content: [...result.content, {
689
+ type: "text",
690
+ text: (await readPackageMaterial("resources/ticket-at-receipt.md")).trim(),
691
+ }],
692
+ };
693
+ }
679
694
  } catch (error) {
680
695
  if (toolThrew) throw error;
681
696
  return failInfrastructure(error, context, toolCallId);
@@ -1 +0,0 @@
1
- 本腿仍无票号。请调用 ak_report_ticket 申报,或在交卷里带上 ticketNumber。只问这一次。