@akagilnc/pi-workflow-roles 0.1.1751
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.
- package/LICENSE +202 -0
- package/README.md +104 -0
- package/README.zh-CN.md +133 -0
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/dist/activation-ledger-git.js +68 -0
- package/dist/activation-ledger-session.js +120 -0
- package/dist/activation-ledger-topology.js +239 -0
- package/dist/activation-reconciliation.js +61 -0
- package/dist/audit-escalation.js +108 -0
- package/dist/auditor-dossier-tool.js +35 -0
- package/dist/canonical-json.js +78 -0
- package/dist/compliance-transport.js +77 -0
- package/dist/doctor-contracts.js +172 -0
- package/dist/dossier-resolution.js +103 -0
- package/dist/evidence-child-executor.js +661 -0
- package/dist/exact-utf8.js +12 -0
- package/dist/git-object-id.js +7 -0
- package/dist/in-process-session.js +50 -0
- package/dist/merger-contracts.js +76 -0
- package/dist/navigator-attendance.js +995 -0
- package/dist/navigator-invocation-identity.js +220 -0
- package/dist/open-tool-schema.js +39 -0
- package/dist/package-contracts/collector-output.js +50 -0
- package/dist/package-contracts/fixer-output.js +72 -0
- package/dist/package-contracts/fixer-packet.js +77 -0
- package/dist/package-contracts/judge-output.js +17 -0
- package/dist/package-contracts/reviewer-output.js +82 -0
- package/dist/package-contracts/terminating-tools.js +173 -0
- package/dist/package-contracts/worker-output.js +13 -0
- package/dist/package-owned-tool-idle.js +104 -0
- package/dist/packaged-role-registry.js +34 -0
- package/dist/public-cli/main.js +23867 -0
- package/dist/public-command-renderer.js +20 -0
- package/dist/reviewer-agent.js +93 -0
- package/dist/reviewer-child-executor.js +23 -0
- package/dist/reviewer-construction.js +95 -0
- package/dist/reviewer-dispatch.js +77 -0
- package/dist/reviewer-execution-ledger.js +160 -0
- package/dist/reviewer-failure-diagnostic.js +17 -0
- package/dist/reviewer-git-snapshot.js +38 -0
- package/dist/reviewer-pinned-git.js +146 -0
- package/dist/reviewer-preflight-error.js +15 -0
- package/dist/reviewer-prompt-identity.js +10 -0
- package/dist/reviewer-scope-prompt.js +21 -0
- package/dist/reviewer-workspace.js +151 -0
- package/dist/sha256.js +5 -0
- package/dist/sitian-record-entry.js +33 -0
- package/dist/stderr-jsonl.js +26 -0
- package/dist/stream-idle-guard.js +75 -0
- package/dist/tool-execution-observation.js +141 -0
- package/dist/uuidv7.js +21 -0
- package/dist/work-subject-identity.js +53 -0
- package/extensions/role-runtime.ts +303 -0
- package/package.json +69 -0
- package/packets/fixer-prerequisites.json +6 -0
- package/packets/fixer-repair.md +5 -0
- package/packets/judge-apply.md +77 -0
- package/packets/judge-authority.md +64 -0
- package/packets/judge-plan.md +55 -0
- package/packets/judge-review.md +49 -0
- package/packets/judge-submission.md +34 -0
- package/resources/methods/code-review/SKILL.md +92 -0
- package/resources/methods/code-review/agents/openai.yaml +3 -0
- package/resources/methods/code-review/provenance.json +26 -0
- package/resources/methods/diagnosing-bugs/SKILL.md +134 -0
- package/resources/methods/diagnosing-bugs/agents/openai.yaml +3 -0
- package/resources/methods/diagnosing-bugs/provenance.json +31 -0
- package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/resources/methods/resolving-merge-conflicts/SKILL.md +14 -0
- package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +3 -0
- package/resources/methods/resolving-merge-conflicts/provenance.json +26 -0
- package/resources/methods/tdd/SKILL.md +38 -0
- package/resources/methods/tdd/agents/openai.yaml +3 -0
- package/resources/methods/tdd/mocking.md +59 -0
- package/resources/methods/tdd/provenance.json +36 -0
- package/resources/methods/tdd/tests.md +77 -0
- package/resources/navigator-route-playbook.md +32 -0
- package/schemas/tool-execution-observation.schema.json +107 -0
- package/scripts/build-package.mjs +65 -0
- package/scripts/generate-tool-execution-observation-schema.ts +7 -0
- package/souls/coder.md +10 -0
- package/souls/collector.md +11 -0
- package/souls/doctor-auditor.md +23 -0
- package/souls/doctor.md +8 -0
- package/souls/fixer-auditor.md +33 -0
- package/souls/fixer.md +13 -0
- package/souls/judge-auditor.md +33 -0
- package/souls/judge.md +74 -0
- package/souls/merger.md +5 -0
- package/souls/navigator.md +5 -0
- package/souls/reviewer-auditor.md +25 -0
- package/souls/reviewer.md +11 -0
- package/src/activation-ledger-git.ts +96 -0
- package/src/activation-ledger-session.ts +188 -0
- package/src/activation-ledger-topology.ts +301 -0
- package/src/activation-ledger.ts +240 -0
- package/src/activation-reconciliation.ts +163 -0
- package/src/activation-trace.ts +38 -0
- package/src/audit-escalation.ts +177 -0
- package/src/auditor-dossier-tool.ts +48 -0
- package/src/auditor-soul.ts +28 -0
- package/src/canonical-json.ts +74 -0
- package/src/canonical-skill-binding.ts +107 -0
- package/src/collector-config.ts +89 -0
- package/src/collector-evidence.ts +461 -0
- package/src/collector-github.ts +656 -0
- package/src/collector-identity.ts +161 -0
- package/src/collector-ledger.ts +827 -0
- package/src/collector-receipt.ts +87 -0
- package/src/collector-role.ts +592 -0
- package/src/collector-tool-schemas.ts +19 -0
- package/src/compliance-transport.ts +130 -0
- package/src/doctor-auditor.ts +53 -0
- package/src/doctor-contracts.ts +166 -0
- package/src/doctor-evidence.ts +47 -0
- package/src/doctor-role.ts +18 -0
- package/src/dossier-resolution.ts +137 -0
- package/src/evidence-child-executor.ts +775 -0
- package/src/exact-utf8.ts +9 -0
- package/src/factory-board.ts +1822 -0
- package/src/git-object-id.ts +11 -0
- package/src/human-format.ts +65 -0
- package/src/in-process-session.ts +78 -0
- package/src/judge-auditor.ts +55 -0
- package/src/judge-recording-anti-forge.ts +53 -0
- package/src/judge-role.ts +160 -0
- package/src/merger-contracts.ts +71 -0
- package/src/merger-git-state.ts +76 -0
- package/src/merger-role.ts +60 -0
- package/src/navigator-attendance.ts +1254 -0
- package/src/navigator-invocation-identity.ts +446 -0
- package/src/open-tool-schema.ts +46 -0
- package/src/package-contracts/collector-output.ts +109 -0
- package/src/package-contracts/fixer-output.ts +81 -0
- package/src/package-contracts/fixer-packet.ts +93 -0
- package/src/package-contracts/judge-output.ts +39 -0
- package/src/package-contracts/reviewer-output.ts +115 -0
- package/src/package-contracts/terminating-tools.ts +259 -0
- package/src/package-contracts/worker-output.ts +36 -0
- package/src/package-owned-tool-idle.ts +134 -0
- package/src/package-resources/method-skill-binding.ts +87 -0
- package/src/package-resources/method-skill.ts +358 -0
- package/src/packaged-role-registry.ts +36 -0
- package/src/public-cli/cli-errors.ts +11 -0
- package/src/public-cli/cli-io.ts +4 -0
- package/src/public-cli/cli.ts +912 -0
- package/src/public-cli/coder-run.ts +575 -0
- package/src/public-cli/collector-run.ts +375 -0
- package/src/public-cli/command-renderer.ts +8 -0
- package/src/public-cli/config.ts +346 -0
- package/src/public-cli/doctor-run.ts +355 -0
- package/src/public-cli/explicit-internal.ts +274 -0
- package/src/public-cli/fixer-run.ts +587 -0
- package/src/public-cli/host-pi-runtime.ts +112 -0
- package/src/public-cli/invocation.ts +1958 -0
- package/src/public-cli/judge-run.ts +507 -0
- package/src/public-cli/main.ts +15 -0
- package/src/public-cli/merger-run.ts +681 -0
- package/src/public-cli/public-run-credentials.ts +71 -0
- package/src/public-cli/registry.ts +153 -0
- package/src/public-cli/reviewer-run.ts +561 -0
- package/src/public-cli/run-lifecycle.ts +884 -0
- package/src/public-cli/settlement.ts +3765 -0
- package/src/public-cli/terminal.ts +325 -0
- package/src/public-command-renderer.ts +43 -0
- package/src/reviewer-agent.ts +94 -0
- package/src/reviewer-auditor.ts +53 -0
- package/src/reviewer-child-executor.ts +31 -0
- package/src/reviewer-construction.ts +137 -0
- package/src/reviewer-dispatch.ts +94 -0
- package/src/reviewer-execution-ledger.ts +206 -0
- package/src/reviewer-failure-diagnostic.ts +18 -0
- package/src/reviewer-git-snapshot.ts +53 -0
- package/src/reviewer-pinned-git.ts +144 -0
- package/src/reviewer-preflight-error.ts +14 -0
- package/src/reviewer-prompt-identity.ts +17 -0
- package/src/reviewer-role.ts +193 -0
- package/src/reviewer-scope-prompt.ts +24 -0
- package/src/reviewer-settlement.ts +63 -0
- package/src/reviewer-workspace.ts +111 -0
- package/src/role-runtime.ts +884 -0
- package/src/sha256.ts +6 -0
- package/src/sitian-record-entry.ts +57 -0
- package/src/stderr-jsonl.ts +28 -0
- package/src/stream-idle-guard.ts +98 -0
- package/src/ticket-snapshot.ts +662 -0
- package/src/ticket-trajectory.ts +1000 -0
- package/src/tool-execution-observation.ts +168 -0
- package/src/uuidv7.ts +1 -0
- package/src/work-subject-identity.ts +94 -0
- package/src/worker-role.ts +434 -0
- package/src/worker-submission-gates.ts +225 -0
|
@@ -0,0 +1,995 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { createAssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
7
|
+
import { Type } from "typebox";
|
|
8
|
+
import { Value } from "typebox/value";
|
|
9
|
+
import {
|
|
10
|
+
NAVIGATOR_INVOCATION_ENTRY,
|
|
11
|
+
mintNavigatorInvocationId
|
|
12
|
+
} from "./navigator-invocation-identity.js";
|
|
13
|
+
import { PACKAGED_ROLE_REGISTRY, packagedRoleMetadata } from "./packaged-role-registry.js";
|
|
14
|
+
import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
|
|
15
|
+
import { activationBookDirectory, resolveActivationLedgerHome } from "./activation-ledger-topology.js";
|
|
16
|
+
import { openInProcessAgentSession } from "./in-process-session.js";
|
|
17
|
+
import { renderPublicAkRoleCommand } from "./public-command-renderer.js";
|
|
18
|
+
import { issueRoot, subjectPath } from "./work-subject-identity.js";
|
|
19
|
+
import { wrapPackageOwnedToolDefinition } from "./package-owned-tool-idle.js";
|
|
20
|
+
const NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
|
|
21
|
+
const NAVIGATOR_PREPARE_TOOL_NAME = "ak_navigator_prepare";
|
|
22
|
+
const NAVIGATOR_DEFAULT_MODEL = "openai-codex/gpt-5.6-luna:max";
|
|
23
|
+
const NAVIGATOR_TARGETS = PACKAGED_ROLE_REGISTRY.map(({ role, phases }) => ({ role, phases }));
|
|
24
|
+
class NavigatorUnavailableError extends Error {
|
|
25
|
+
unavailableSource;
|
|
26
|
+
unavailableCause;
|
|
27
|
+
originalCause;
|
|
28
|
+
constructor(source, message, cause = source, originalCause) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = "NavigatorUnavailableError";
|
|
31
|
+
this.unavailableSource = source;
|
|
32
|
+
this.unavailableCause = cause;
|
|
33
|
+
this.originalCause = originalCause;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function navigatorProviderFailureFromStatus(status) {
|
|
37
|
+
if (status === 401 || status === 403) return { source: "auth", cause: "auth" };
|
|
38
|
+
if (status === 429) return { source: "quota", cause: "quota" };
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
function navigatorProviderFailureFromCode(code) {
|
|
42
|
+
if (typeof code === "number") {
|
|
43
|
+
return navigatorProviderFailureFromStatus(code);
|
|
44
|
+
}
|
|
45
|
+
if (typeof code !== "string") return void 0;
|
|
46
|
+
if (code === "unauthorized" || code === "authentication_failed") return { source: "auth", cause: "auth" };
|
|
47
|
+
if (code === "insufficient_quota" || code === "quota_exhausted") return { source: "quota", cause: "quota" };
|
|
48
|
+
if (code === "transport_error") return { source: "transport", cause: "transport" };
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
function navigatorProviderFailureFromError(error) {
|
|
52
|
+
if (!exactRecord(error)) return void 0;
|
|
53
|
+
const statusCode = typeof error.statusCode === "number" ? error.statusCode : typeof error.status === "number" ? error.status : void 0;
|
|
54
|
+
return navigatorProviderFailureFromStatus(statusCode) ?? navigatorProviderFailureFromCode(error.code);
|
|
55
|
+
}
|
|
56
|
+
function navigatorProviderFailureFromDiagnostics(diagnostics) {
|
|
57
|
+
if (!Array.isArray(diagnostics)) return void 0;
|
|
58
|
+
for (const diagnostic of diagnostics) {
|
|
59
|
+
if (!exactRecord(diagnostic)) continue;
|
|
60
|
+
if (diagnostic.type === "provider_transport_failure") return { source: "transport", cause: "transport" };
|
|
61
|
+
if (exactRecord(diagnostic.error)) {
|
|
62
|
+
const fromCode = navigatorProviderFailureFromCode(diagnostic.error.code);
|
|
63
|
+
if (fromCode !== void 0) return fromCode;
|
|
64
|
+
}
|
|
65
|
+
if (exactRecord(diagnostic.details)) {
|
|
66
|
+
const status = typeof diagnostic.details.status === "number" ? diagnostic.details.status : typeof diagnostic.details.statusCode === "number" ? diagnostic.details.statusCode : void 0;
|
|
67
|
+
const fromStatus = navigatorProviderFailureFromStatus(status);
|
|
68
|
+
if (fromStatus !== void 0) return fromStatus;
|
|
69
|
+
const fromCode = navigatorProviderFailureFromCode(diagnostic.details.code);
|
|
70
|
+
if (fromCode !== void 0) return fromCode;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
const navigatorProviderFailureSchema = Type.Object({
|
|
76
|
+
source: Type.Union([Type.Literal("context"), Type.Literal("session"), Type.Literal("model"), Type.Literal("thinking"), Type.Literal("auth"), Type.Literal("quota"), Type.Literal("transport"), Type.Literal("unknown")]),
|
|
77
|
+
cause: Type.Union([Type.Literal("context"), Type.Literal("session"), Type.Literal("model"), Type.Literal("thinking"), Type.Literal("auth"), Type.Literal("quota"), Type.Literal("transport"), Type.Literal("unknown")])
|
|
78
|
+
}, { additionalProperties: false });
|
|
79
|
+
function navigatorProviderFailure(message, source, cause = source) {
|
|
80
|
+
const fact = { source, cause };
|
|
81
|
+
if (!Value.Check(navigatorProviderFailureSchema, fact)) throw new TypeError("Navigator provider failure fact is not typed");
|
|
82
|
+
return Object.assign(message, { navigatorFailure: fact });
|
|
83
|
+
}
|
|
84
|
+
function navigatorUnavailableError(source, error, cause = source) {
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return error instanceof NavigatorUnavailableError ? error : new NavigatorUnavailableError(source, message, cause, error);
|
|
87
|
+
}
|
|
88
|
+
function navigatorAdviceConsistentWithSettlement(next, settlement) {
|
|
89
|
+
if (settlement.kind !== "accepted") return true;
|
|
90
|
+
if (settlement.status === "unfinished" && next.role === "judge") return false;
|
|
91
|
+
if (settlement.role === "fixer" && settlement.phase === "apply" && settlement.status === "completed" && next.role === "fixer" && next.phase === "apply") return false;
|
|
92
|
+
if (next.role !== "merger") return true;
|
|
93
|
+
return settlement.role === "judge" && settlement.status === "converged";
|
|
94
|
+
}
|
|
95
|
+
const prepareSchema = Type.Object({}, { additionalProperties: true });
|
|
96
|
+
const ROUTE_ENTRY = "ak-navigator-route";
|
|
97
|
+
const CONTEXT_ENTRY = "ak-navigator-context";
|
|
98
|
+
const INVOCATION_ENTRY = NAVIGATOR_INVOCATION_ENTRY;
|
|
99
|
+
const SETTLEMENT_ENTRY = "ak-navigator-settlement";
|
|
100
|
+
const targetRoles = new Set(NAVIGATOR_TARGETS.map(({ role }) => role));
|
|
101
|
+
const unavailableKeys = /* @__PURE__ */ new Set(["context", "session", "model", "thinking", "auth", "quota", "transport", "unknown"]);
|
|
102
|
+
function unavailableKey(value) {
|
|
103
|
+
return typeof value === "string" && unavailableKeys.has(value) ? value : void 0;
|
|
104
|
+
}
|
|
105
|
+
function exactRecord(value) {
|
|
106
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
107
|
+
}
|
|
108
|
+
function targetIsValid(value) {
|
|
109
|
+
if (!exactRecord(value) || !targetRoles.has(String(value.role))) return false;
|
|
110
|
+
const metadata = packagedRoleMetadata(String(value.role));
|
|
111
|
+
return metadata !== void 0 && metadata.phases.includes(value.phase);
|
|
112
|
+
}
|
|
113
|
+
function normalizeTarget(value) {
|
|
114
|
+
if (!exactRecord(value)) return void 0;
|
|
115
|
+
const role = typeof value.role === "string" ? value.role.trim() : "";
|
|
116
|
+
if (!targetRoles.has(role)) return void 0;
|
|
117
|
+
const metadata = packagedRoleMetadata(role);
|
|
118
|
+
if (metadata === void 0) return void 0;
|
|
119
|
+
if (value.phase === void 0 || value.phase === null) {
|
|
120
|
+
return { role, phase: null };
|
|
121
|
+
}
|
|
122
|
+
if (value.phase === "plan" || value.phase === "apply") {
|
|
123
|
+
if (metadata.phases.includes(value.phase)) {
|
|
124
|
+
return { role, phase: value.phase };
|
|
125
|
+
}
|
|
126
|
+
return { role, phase: null };
|
|
127
|
+
}
|
|
128
|
+
return void 0;
|
|
129
|
+
}
|
|
130
|
+
function normalizeMatches(value) {
|
|
131
|
+
if (!exactRecord(value)) return void 0;
|
|
132
|
+
if (typeof value.role !== "string" || value.role.trim() === "") return void 0;
|
|
133
|
+
if (value.kind !== "accepted") return void 0;
|
|
134
|
+
let phase;
|
|
135
|
+
if (value.phase === void 0 || value.phase === null) phase = null;
|
|
136
|
+
else if (value.phase === "plan" || value.phase === "apply") phase = value.phase;
|
|
137
|
+
else return void 0;
|
|
138
|
+
if (value.statuses !== void 0) {
|
|
139
|
+
if (!Array.isArray(value.statuses) || value.statuses.some((status) => typeof status !== "string" || status.trim() === "")) {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
role: value.role,
|
|
144
|
+
phase,
|
|
145
|
+
kind: "accepted",
|
|
146
|
+
statuses: [...value.statuses]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { role: value.role, phase, kind: "accepted" };
|
|
150
|
+
}
|
|
151
|
+
function normalizeCandidate(value) {
|
|
152
|
+
if (!exactRecord(value)) return void 0;
|
|
153
|
+
const next = normalizeTarget(value.next);
|
|
154
|
+
const route = Array.isArray(value.route) ? value.route.map(normalizeTarget).filter((target) => target !== void 0) : void 0;
|
|
155
|
+
const matches = normalizeMatches(value.matches);
|
|
156
|
+
const id = typeof value.id === "string" && value.id.trim() !== "" ? value.id : void 0;
|
|
157
|
+
const reason = typeof value.reason === "string" && value.reason.trim() !== "" ? value.reason : void 0;
|
|
158
|
+
return {
|
|
159
|
+
...id === void 0 ? {} : { id },
|
|
160
|
+
...matches === void 0 ? {} : { matches },
|
|
161
|
+
...route === void 0 || route.length === 0 ? {} : { route },
|
|
162
|
+
...next === void 0 ? {} : { next },
|
|
163
|
+
...reason === void 0 ? {} : { reason }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function normalizePrepareOutput(value) {
|
|
167
|
+
if (!exactRecord(value) || !Array.isArray(value.candidates)) return [];
|
|
168
|
+
return value.candidates.map(normalizeCandidate).filter((candidate) => candidate !== void 0);
|
|
169
|
+
}
|
|
170
|
+
function routeEqual(a, b) {
|
|
171
|
+
return a !== void 0 && a.length === b.length && a.every((target, index) => target.role === b[index].role && target.phase === b[index].phase);
|
|
172
|
+
}
|
|
173
|
+
function routeText(route) {
|
|
174
|
+
return route.map((target) => target.phase === null ? target.role : `${target.role} ${target.phase}`).join(" \u2192 ");
|
|
175
|
+
}
|
|
176
|
+
function targetText(target) {
|
|
177
|
+
return target.phase === null ? target.role : `${target.role} ${target.phase}`;
|
|
178
|
+
}
|
|
179
|
+
function oneLine(value) {
|
|
180
|
+
return value.split(/\r?\n/, 1)[0].trim();
|
|
181
|
+
}
|
|
182
|
+
function navigatorSubjectKey(subjectRoot, subject, provenance = "role_input") {
|
|
183
|
+
if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
|
|
184
|
+
if (provenance === "placeholder") return subjectRoot;
|
|
185
|
+
const normalized = subject.trim().replace(/\s+/g, " ");
|
|
186
|
+
if (normalized === "") return subjectRoot;
|
|
187
|
+
return `${subjectRoot}#${createHash("sha256").update(normalized).digest("hex").slice(0, 32)}`;
|
|
188
|
+
}
|
|
189
|
+
function navigatorSubjectKeyForInput(subjectRoot, reference, cwd = process.cwd()) {
|
|
190
|
+
if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
|
|
191
|
+
const resolvedReference = resolve(cwd, reference);
|
|
192
|
+
const marker = "/runs/";
|
|
193
|
+
if (resolvedReference.includes(marker)) {
|
|
194
|
+
return subjectRoot;
|
|
195
|
+
}
|
|
196
|
+
return navigatorSubjectKey(subjectRoot, resolvedReference);
|
|
197
|
+
}
|
|
198
|
+
function subjectDirectory(cwd, subjectKey) {
|
|
199
|
+
const book = activationBookDirectory(
|
|
200
|
+
resolveActivationLedgerHome(),
|
|
201
|
+
resolveBookKeyFromGit(cwd)
|
|
202
|
+
);
|
|
203
|
+
const digest = createHash("sha256").update(subjectKey).digest("hex").slice(0, 32);
|
|
204
|
+
return join(book, "navigator", digest);
|
|
205
|
+
}
|
|
206
|
+
function navigatorModelSettingPath() {
|
|
207
|
+
return join(process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent"), "navigator-model.json");
|
|
208
|
+
}
|
|
209
|
+
async function readNavigatorModelSetting(path = navigatorModelSettingPath()) {
|
|
210
|
+
try {
|
|
211
|
+
const raw = JSON.parse(await readFile(path, "utf8"));
|
|
212
|
+
if (!exactRecord(raw) || typeof raw.model !== "string" || raw.model.trim() === "") throw new Error("Navigator model setting is malformed");
|
|
213
|
+
return raw.model;
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return NAVIGATOR_DEFAULT_MODEL;
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function writeNavigatorModelSetting(model, path = navigatorModelSettingPath()) {
|
|
220
|
+
const normalized = model.trim();
|
|
221
|
+
parseNavigatorModelSetting(normalized);
|
|
222
|
+
await mkdir(dirname(path), { recursive: true });
|
|
223
|
+
await writeFile(path, JSON.stringify({ model: normalized }) + "\n", "utf8");
|
|
224
|
+
}
|
|
225
|
+
function parseNavigatorModelSetting(value) {
|
|
226
|
+
const slash = value.indexOf("/");
|
|
227
|
+
if (slash <= 0 || slash === value.length - 1) throw new Error("Navigator model setting must be provider/model[:max]");
|
|
228
|
+
const provider = value.slice(0, slash);
|
|
229
|
+
const modelWithThinking = value.slice(slash + 1);
|
|
230
|
+
const colon = modelWithThinking.lastIndexOf(":");
|
|
231
|
+
const suffix = colon < 0 ? void 0 : modelWithThinking.slice(colon + 1);
|
|
232
|
+
if (suffix !== void 0 && suffix !== "max") throw new Error("Navigator model setting must use :max or omit the thinking suffix");
|
|
233
|
+
const model = colon < 0 ? modelWithThinking : modelWithThinking.slice(0, colon);
|
|
234
|
+
if (model === "") throw new Error("Navigator model setting must include a model");
|
|
235
|
+
return { provider, model, thinkingLevel: suffix === "max" ? "max" : "off" };
|
|
236
|
+
}
|
|
237
|
+
function createNavigatorPrepareTool(onOutput) {
|
|
238
|
+
return wrapPackageOwnedToolDefinition({
|
|
239
|
+
name: NAVIGATOR_PREPARE_TOOL_NAME,
|
|
240
|
+
label: "Navigator preparation",
|
|
241
|
+
description: "Submit Navigator direction advice. Provide candidates with next.role (phase when meaningful). route/matches/reason/command are optional context, not acceptance gates.",
|
|
242
|
+
parameters: prepareSchema,
|
|
243
|
+
async execute(_id, value) {
|
|
244
|
+
onOutput(value);
|
|
245
|
+
return { content: [{ type: "text", text: "Navigator preparation accepted" }], details: value, terminate: true };
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function selectNavigatorCandidate(candidates, settlement) {
|
|
250
|
+
if (settlement.kind !== "accepted") return void 0;
|
|
251
|
+
const usable = candidates.filter((candidate) => candidate.next !== void 0);
|
|
252
|
+
if (usable.length === 0) return void 0;
|
|
253
|
+
const matched = usable.filter(
|
|
254
|
+
(candidate) => candidate.matches !== void 0 && candidate.matches.role === settlement.role && candidate.matches.phase === settlement.phase
|
|
255
|
+
);
|
|
256
|
+
if (matched.length > 0) {
|
|
257
|
+
if (settlement.status !== void 0) {
|
|
258
|
+
const statusSpecific = matched.find((candidate) => candidate.matches?.statuses?.includes(settlement.status) === true);
|
|
259
|
+
if (statusSpecific !== void 0) return statusSpecific;
|
|
260
|
+
}
|
|
261
|
+
return matched.find((candidate) => candidate.matches?.statuses === void 0);
|
|
262
|
+
}
|
|
263
|
+
return usable.find((candidate) => candidate.matches === void 0);
|
|
264
|
+
}
|
|
265
|
+
function formatNavigatorReport(report) {
|
|
266
|
+
const playbookFailure = report.routePlaybookReadFailure === void 0 ? [] : [`\u8DEF\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${oneLine(report.routePlaybookReadFailure)}`];
|
|
267
|
+
if (report.disposition === "no-advice") return playbookFailure.join("\n");
|
|
268
|
+
if (report.disposition === "unavailable") return [...playbookFailure, `\u5BFC\u822A\u4E0D\u53EF\u7528\uFF1A${oneLine(report.unavailableReason ?? "\u672A\u80FD\u5B8C\u6210\u5BFC\u822A\u51C6\u5907")}`].join("\n");
|
|
269
|
+
if (report.disposition === "arrival") return [...playbookFailure, oneLine(report.arrivalMessage ?? "\u5DF2\u5230\u8FBE\u76EE\u7684\u5730")].join("\n");
|
|
270
|
+
return [
|
|
271
|
+
...playbookFailure,
|
|
272
|
+
...report.route === void 0 ? [] : [`\u8DEF\u7EBF\uFF1A${routeText(report.route)}`],
|
|
273
|
+
`\u4E0B\u4E00\u6B65\uFF1A${targetText(report.next)}`,
|
|
274
|
+
...report.reason === void 0 || report.reason.trim() === "" ? [] : [`\u7406\u7531\uFF1A${oneLine(report.reason)}`],
|
|
275
|
+
...report.command === void 0 || report.command.trim() === "" ? [] : [`\u547D\u4EE4\uFF1A${oneLine(report.command)}`]
|
|
276
|
+
].join("\n");
|
|
277
|
+
}
|
|
278
|
+
function settlementNavigationFromEvent(event) {
|
|
279
|
+
if (event.disposition !== "recommendation") return void 0;
|
|
280
|
+
if (event.next === void 0) return void 0;
|
|
281
|
+
return {
|
|
282
|
+
disposition: "recommendation",
|
|
283
|
+
...event.route === void 0 ? {} : { route: event.route },
|
|
284
|
+
next: event.next,
|
|
285
|
+
...event.reason === void 0 ? {} : { reason: event.reason },
|
|
286
|
+
...event.command === void 0 ? {} : { command: event.command }
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function appendNavigatorReportToContent(content, reportText) {
|
|
290
|
+
if (reportText === "") return content.slice();
|
|
291
|
+
const parts = content.slice();
|
|
292
|
+
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
293
|
+
const part = parts[index];
|
|
294
|
+
if (part !== void 0 && part.type === "text" && typeof part.text === "string") {
|
|
295
|
+
parts[index] = { ...part, type: "text", text: `${part.text}
|
|
296
|
+
${reportText}` };
|
|
297
|
+
return parts;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return [...parts, { type: "text", text: reportText }];
|
|
301
|
+
}
|
|
302
|
+
function decorateSettlementWithNavigation(event, presentation) {
|
|
303
|
+
if (presentation === void 0) return void 0;
|
|
304
|
+
if (settlementNavigationFromEvent(presentation.event) === void 0) return void 0;
|
|
305
|
+
const { routePlaybookReadFailure: _advisoryFailure, ...receiptReport } = presentation.report;
|
|
306
|
+
const reportText = formatNavigatorReport(receiptReport);
|
|
307
|
+
if (reportText === "") return void 0;
|
|
308
|
+
return {
|
|
309
|
+
content: appendNavigatorReportToContent(event.content, reportText),
|
|
310
|
+
details: event.details
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function createNavigatorAttendance(options) {
|
|
314
|
+
let preparation;
|
|
315
|
+
let sessionReady;
|
|
316
|
+
let session;
|
|
317
|
+
let subjectKey = options.subjectKey;
|
|
318
|
+
let subject = options.subject;
|
|
319
|
+
let authority = options.authority;
|
|
320
|
+
let contextError = options.contextError;
|
|
321
|
+
let sessionDir = options.sessionDir;
|
|
322
|
+
let candidates;
|
|
323
|
+
const invocationPrincipal = options.invocationId ?? mintNavigatorInvocationId();
|
|
324
|
+
let activeInvocationId = invocationPrincipal;
|
|
325
|
+
let previousRoute;
|
|
326
|
+
let outputSink;
|
|
327
|
+
let settlementTail = Promise.resolve();
|
|
328
|
+
let settlementFailure;
|
|
329
|
+
let preparationFailure;
|
|
330
|
+
let routePlaybookReadFailure;
|
|
331
|
+
let disposed = false;
|
|
332
|
+
let warmedHelp;
|
|
333
|
+
const loadLiveHelp = async () => {
|
|
334
|
+
try {
|
|
335
|
+
return await Promise.all(
|
|
336
|
+
NAVIGATOR_TARGETS.map(async ({ role }) => ({
|
|
337
|
+
role,
|
|
338
|
+
help: await options.loadRoleHelp(role)
|
|
339
|
+
}))
|
|
340
|
+
);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
throw navigatorUnavailableError("transport", error);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const unavailable = (invocationId, reason) => {
|
|
346
|
+
const failure = reason instanceof NavigatorUnavailableError ? reason : navigatorUnavailableError("unknown", reason);
|
|
347
|
+
return {
|
|
348
|
+
disposition: "unavailable",
|
|
349
|
+
unavailableReason: failure.message,
|
|
350
|
+
unavailableSource: failure.unavailableSource,
|
|
351
|
+
unavailableCause: failure.unavailableCause
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
let routePlaybookSettlement;
|
|
355
|
+
let prepareBoundSettlement;
|
|
356
|
+
const prepare = async () => {
|
|
357
|
+
const boundSettlement = prepareBoundSettlement;
|
|
358
|
+
prepareBoundSettlement = void 0;
|
|
359
|
+
const invocationId = invocationPrincipal;
|
|
360
|
+
activeInvocationId = invocationId;
|
|
361
|
+
if (contextError !== void 0) throw navigatorUnavailableError("context", contextError);
|
|
362
|
+
if (typeof authority !== "string" || authority.trim() === "") {
|
|
363
|
+
throw navigatorUnavailableError(
|
|
364
|
+
"context",
|
|
365
|
+
new Error("controlling authority content was not supplied as typed work context")
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
let soul;
|
|
369
|
+
let modelSetting;
|
|
370
|
+
let help;
|
|
371
|
+
let routePlaybook = "";
|
|
372
|
+
routePlaybookReadFailure = void 0;
|
|
373
|
+
const soulPromise = (async () => {
|
|
374
|
+
try {
|
|
375
|
+
const text = (await options.loadSoul()).trim();
|
|
376
|
+
if (!text) throw new Error("Navigator soul is empty");
|
|
377
|
+
return text;
|
|
378
|
+
} catch (error) {
|
|
379
|
+
throw navigatorUnavailableError("context", error);
|
|
380
|
+
}
|
|
381
|
+
})();
|
|
382
|
+
const routePlaybookPromise = (async () => {
|
|
383
|
+
if (options.loadRoutePlaybook === void 0) return "";
|
|
384
|
+
try {
|
|
385
|
+
return await options.loadRoutePlaybook();
|
|
386
|
+
} catch (error) {
|
|
387
|
+
routePlaybookReadFailure = error instanceof Error ? error.message : String(error);
|
|
388
|
+
return "";
|
|
389
|
+
}
|
|
390
|
+
})();
|
|
391
|
+
routePlaybookSettlement = routePlaybookPromise.then(() => void 0);
|
|
392
|
+
const modelPromise = (async () => {
|
|
393
|
+
try {
|
|
394
|
+
return await readNavigatorModelSetting(options.modelSettingPath);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
throw navigatorUnavailableError("model", error);
|
|
397
|
+
}
|
|
398
|
+
})();
|
|
399
|
+
const helpPromise = warmedHelp ?? loadLiveHelp();
|
|
400
|
+
warmedHelp = void 0;
|
|
401
|
+
[soul, routePlaybook, modelSetting, help] = await Promise.all([
|
|
402
|
+
soulPromise,
|
|
403
|
+
routePlaybookPromise,
|
|
404
|
+
modelPromise,
|
|
405
|
+
helpPromise
|
|
406
|
+
]);
|
|
407
|
+
let model;
|
|
408
|
+
try {
|
|
409
|
+
model = parseNavigatorModelSetting(modelSetting);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
throw navigatorUnavailableError("model", error);
|
|
412
|
+
}
|
|
413
|
+
const helpContext = help.map(({ role, help: text }) => `<role_help role="${role}">
|
|
414
|
+
${text}
|
|
415
|
+
</role_help>`).join("\n");
|
|
416
|
+
let output;
|
|
417
|
+
outputSink = (value) => {
|
|
418
|
+
if (output !== void 0) throw new Error("Navigator preparation must submit exactly one typed candidate batch");
|
|
419
|
+
output = value;
|
|
420
|
+
};
|
|
421
|
+
const tool = createNavigatorPrepareTool((value) => {
|
|
422
|
+
outputSink?.(value);
|
|
423
|
+
});
|
|
424
|
+
if (session === void 0) {
|
|
425
|
+
sessionReady = (async () => {
|
|
426
|
+
let created;
|
|
427
|
+
try {
|
|
428
|
+
created = await options.createSession({ context: options.context, sessionDir, ...options.modelSettingPath === void 0 ? {} : { modelSettingPath: options.modelSettingPath }, tool });
|
|
429
|
+
} catch (error) {
|
|
430
|
+
throw navigatorUnavailableError("session", error);
|
|
431
|
+
}
|
|
432
|
+
if (disposed) {
|
|
433
|
+
created.dispose();
|
|
434
|
+
throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
await created.setModel?.(modelSetting, model.thinkingLevel);
|
|
438
|
+
if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
439
|
+
if (created.getThinkingLevel?.() !== void 0 && created.getThinkingLevel() !== model.thinkingLevel) {
|
|
440
|
+
throw new NavigatorUnavailableError("thinking", `Navigator thinking level ${model.thinkingLevel} is unavailable for ${modelSetting}`);
|
|
441
|
+
}
|
|
442
|
+
created.appendEntry(INVOCATION_ENTRY, { invocationId, role: options.role, phase: options.phase, subjectKey });
|
|
443
|
+
if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
444
|
+
session = created;
|
|
445
|
+
return created;
|
|
446
|
+
} catch (error) {
|
|
447
|
+
if (session !== created) created.dispose();
|
|
448
|
+
throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("session", error);
|
|
449
|
+
}
|
|
450
|
+
})();
|
|
451
|
+
await sessionReady;
|
|
452
|
+
sessionReady = void 0;
|
|
453
|
+
} else {
|
|
454
|
+
try {
|
|
455
|
+
await session.setModel?.(modelSetting, model.thinkingLevel);
|
|
456
|
+
if (session.getThinkingLevel?.() !== void 0 && session.getThinkingLevel() !== model.thinkingLevel) {
|
|
457
|
+
throw new NavigatorUnavailableError("thinking", `Navigator thinking level ${model.thinkingLevel} is unavailable for ${modelSetting}`);
|
|
458
|
+
}
|
|
459
|
+
} catch (error) {
|
|
460
|
+
throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("session", error);
|
|
461
|
+
}
|
|
462
|
+
session.appendEntry(INVOCATION_ENTRY, { invocationId, role: options.role, phase: options.phase, subjectKey });
|
|
463
|
+
}
|
|
464
|
+
if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
465
|
+
const activeSession = session;
|
|
466
|
+
if (activeSession === void 0) throw new Error("Navigator session was not created");
|
|
467
|
+
const prior = activeSession.entries().filter((entry) => exactRecord(entry) && entry.type === "custom" && entry.customType === ROUTE_ENTRY && exactRecord(entry.data) && entry.data.subjectKey === subjectKey).at(-1)?.data;
|
|
468
|
+
if (exactRecord(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target))) {
|
|
469
|
+
previousRoute = prior.route.map((target) => ({ role: target.role, phase: target.phase }));
|
|
470
|
+
}
|
|
471
|
+
const publicSettlementHistory = activeSession.entries().filter((entry) => exactRecord(entry) && entry.type === "custom" && entry.customType === SETTLEMENT_ENTRY && exactRecord(entry.data)).slice(-8).map((entry) => entry.data);
|
|
472
|
+
const projection = {
|
|
473
|
+
subjectKey,
|
|
474
|
+
subject,
|
|
475
|
+
authority,
|
|
476
|
+
currentRole: { role: options.role, phase: options.phase },
|
|
477
|
+
...boundSettlement === void 0 ? {} : { currentSettlement: boundSettlement },
|
|
478
|
+
priorRoute: exactRecord(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target)) ? prior.route.map((target) => ({ role: target.role, phase: target.phase })) : null,
|
|
479
|
+
publicSettlementHistory,
|
|
480
|
+
liveRoleHelp: help
|
|
481
|
+
};
|
|
482
|
+
activeSession.appendEntry(CONTEXT_ENTRY, projection);
|
|
483
|
+
const request = [
|
|
484
|
+
"Act as the Navigator direction advisor. Submit one next-step advice batch; do not execute or invoke any role.",
|
|
485
|
+
`<navigator_soul>
|
|
486
|
+
${soul}
|
|
487
|
+
</navigator_soul>`,
|
|
488
|
+
...routePlaybookReadFailure === void 0 ? [
|
|
489
|
+
`<route_playbook>
|
|
490
|
+
${routePlaybook}
|
|
491
|
+
</route_playbook>`,
|
|
492
|
+
"The route playbook is advisory material only. Exercise independent judgment: adopt, alter, or ignore it; the caller may also deviate."
|
|
493
|
+
] : ["The optional route playbook could not be read. Continue independent judgment from the other supplied materials."],
|
|
494
|
+
`<work_subject>
|
|
495
|
+
${subject}
|
|
496
|
+
</work_subject>`,
|
|
497
|
+
`<controlling_authority>
|
|
498
|
+
${authority}
|
|
499
|
+
</controlling_authority>`,
|
|
500
|
+
`<current_role>
|
|
501
|
+
${JSON.stringify({ role: options.role, phase: options.phase })}
|
|
502
|
+
</current_role>`,
|
|
503
|
+
...boundSettlement === void 0 ? [] : [
|
|
504
|
+
`<current_settlement>
|
|
505
|
+
${JSON.stringify(boundSettlement)}
|
|
506
|
+
</current_settlement>`,
|
|
507
|
+
"The current role has just reached this typed settlement. Recommend the next packaged role AFTER this settlement.",
|
|
508
|
+
"public_settlement_history is prior background only \u2014 a prior terminal does not consume or replace the work this settlement just produced."
|
|
509
|
+
],
|
|
510
|
+
`<prior_route>
|
|
511
|
+
${JSON.stringify(prior ?? null)}
|
|
512
|
+
</prior_route>`,
|
|
513
|
+
`<public_settlement_history>
|
|
514
|
+
${JSON.stringify(projection.publicSettlementHistory)}
|
|
515
|
+
</public_settlement_history>`,
|
|
516
|
+
...boundSettlement === void 0 ? [
|
|
517
|
+
"Preparation is speculative while the current role still runs. Prefer candidates[].matches keyed to plausible accepted outcomes of the current role; prior history must not substitute for the current role's work."
|
|
518
|
+
] : [],
|
|
519
|
+
`<live_role_help>
|
|
520
|
+
${helpContext}
|
|
521
|
+
</live_role_help>`,
|
|
522
|
+
`Use model setting ${JSON.stringify(modelSetting)} for this call. Return exactly one ${NAVIGATOR_PREPARE_TOOL_NAME} call.`,
|
|
523
|
+
"v1 requires a usable next direction: candidates[].next.role, with phase only when present and meaningful. route, matches, id, reason, and command are optional context \u2014 never retry to satisfy optional shape.",
|
|
524
|
+
"Do not put task-specific paths, prompts, packets, or Skill bindings in any field. Command display is rendered by the host from next, not from model prose."
|
|
525
|
+
].join("\n\n");
|
|
526
|
+
try {
|
|
527
|
+
try {
|
|
528
|
+
if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
529
|
+
await activeSession.prompt(request);
|
|
530
|
+
} catch (error) {
|
|
531
|
+
throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("transport", error);
|
|
532
|
+
}
|
|
533
|
+
if (output === void 0) {
|
|
534
|
+
const nativeFailure = [...activeSession.entries()].reverse().find((entry) => {
|
|
535
|
+
if (!exactRecord(entry) || entry.type !== "message" || !exactRecord(entry.message)) return false;
|
|
536
|
+
return entry.message.role === "assistant" && typeof entry.message.errorMessage === "string" && entry.message.errorMessage.trim() !== "";
|
|
537
|
+
});
|
|
538
|
+
const nativeMessage = exactRecord(nativeFailure) && exactRecord(nativeFailure.message) ? nativeFailure.message : void 0;
|
|
539
|
+
const errorMessage = nativeMessage !== void 0 && typeof nativeMessage.errorMessage === "string" ? nativeMessage.errorMessage : "Navigator did not submit direction advice";
|
|
540
|
+
const providerFailure = activeSession.providerFailure?.();
|
|
541
|
+
const source = providerFailure?.source ?? "unknown";
|
|
542
|
+
const cause = providerFailure?.cause ?? source;
|
|
543
|
+
throw navigatorUnavailableError(source, errorMessage, cause);
|
|
544
|
+
}
|
|
545
|
+
candidates = normalizePrepareOutput(output);
|
|
546
|
+
return candidates;
|
|
547
|
+
} finally {
|
|
548
|
+
outputSink = void 0;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
return {
|
|
552
|
+
setWorkContext(next) {
|
|
553
|
+
if (next.subjectKey !== subjectKey && session !== void 0) {
|
|
554
|
+
session.dispose();
|
|
555
|
+
session = void 0;
|
|
556
|
+
previousRoute = void 0;
|
|
557
|
+
}
|
|
558
|
+
subjectKey = next.subjectKey;
|
|
559
|
+
subject = next.subject;
|
|
560
|
+
authority = next.authority;
|
|
561
|
+
contextError = next.contextError;
|
|
562
|
+
sessionDir = options.sessionDirectory?.(next.subjectKey) ?? options.sessionDir;
|
|
563
|
+
},
|
|
564
|
+
/**
|
|
565
|
+
* Start live-help subprocesses during activation without beginning full
|
|
566
|
+
* preparation. Next prepare() consumes the warm result; a later prepare
|
|
567
|
+
* reloads so live help edits remain visible.
|
|
568
|
+
*/
|
|
569
|
+
warmHelp() {
|
|
570
|
+
if (disposed || warmedHelp !== void 0 || preparation !== void 0) return;
|
|
571
|
+
warmedHelp = loadLiveHelp();
|
|
572
|
+
void warmedHelp.catch(() => void 0);
|
|
573
|
+
},
|
|
574
|
+
prepare() {
|
|
575
|
+
if (disposed || preparation !== void 0) return;
|
|
576
|
+
preparationFailure = void 0;
|
|
577
|
+
preparation = prepare();
|
|
578
|
+
void preparation.catch((error) => {
|
|
579
|
+
preparationFailure = error;
|
|
580
|
+
});
|
|
581
|
+
},
|
|
582
|
+
isPreparing() {
|
|
583
|
+
return preparation !== void 0 || sessionReady !== void 0;
|
|
584
|
+
},
|
|
585
|
+
knownRoutePlaybookReadFailure() {
|
|
586
|
+
return routePlaybookReadFailure;
|
|
587
|
+
},
|
|
588
|
+
settle(settlement) {
|
|
589
|
+
const next = settlementTail.then(() => settleOnce(settlement));
|
|
590
|
+
settlementTail = next.catch((error) => {
|
|
591
|
+
settlementFailure = error;
|
|
592
|
+
});
|
|
593
|
+
return next;
|
|
594
|
+
},
|
|
595
|
+
dispose() {
|
|
596
|
+
disposed = true;
|
|
597
|
+
session?.dispose();
|
|
598
|
+
session = void 0;
|
|
599
|
+
activeInvocationId = void 0;
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
async function settleOnce(settlement) {
|
|
603
|
+
const invocationId = activeInvocationId ?? invocationPrincipal;
|
|
604
|
+
let report;
|
|
605
|
+
if (settlement.kind === "human_decision" || settlement.kind === "role_infrastructure_failure") {
|
|
606
|
+
if (sessionReady !== void 0) {
|
|
607
|
+
try {
|
|
608
|
+
await sessionReady;
|
|
609
|
+
} catch (error) {
|
|
610
|
+
preparationFailure ??= error;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (preparation !== void 0) {
|
|
614
|
+
try {
|
|
615
|
+
await preparation;
|
|
616
|
+
} catch (error) {
|
|
617
|
+
preparationFailure ??= error;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.kind === "human_decision" ? { status: settlement.status } : {} });
|
|
621
|
+
if (preparationFailure !== void 0) {
|
|
622
|
+
report = unavailable(invocationId, preparationFailure);
|
|
623
|
+
} else {
|
|
624
|
+
report = { disposition: "no-advice" };
|
|
625
|
+
}
|
|
626
|
+
} else if (settlement.kind === "arrival") {
|
|
627
|
+
if (sessionReady !== void 0) {
|
|
628
|
+
try {
|
|
629
|
+
await sessionReady;
|
|
630
|
+
} catch (error) {
|
|
631
|
+
preparationFailure ??= error;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (preparation !== void 0) {
|
|
635
|
+
try {
|
|
636
|
+
await preparation;
|
|
637
|
+
} catch (error) {
|
|
638
|
+
preparationFailure ??= error;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
report = preparationFailure === void 0 ? { disposition: "arrival", arrivalMessage: settlement.message ?? "\u5DF2\u5230\u8FBE\u76EE\u7684\u5730" } : unavailable(invocationId, preparationFailure);
|
|
642
|
+
} else if (preparation === void 0) {
|
|
643
|
+
report = unavailable(invocationId, "Navigator preparation did not start");
|
|
644
|
+
} else {
|
|
645
|
+
try {
|
|
646
|
+
if (sessionReady !== void 0) await sessionReady;
|
|
647
|
+
let prepared = await preparation;
|
|
648
|
+
session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
|
|
649
|
+
let selected = selectNavigatorCandidate(prepared, settlement);
|
|
650
|
+
if (selected?.next !== void 0 && !navigatorAdviceConsistentWithSettlement(selected.next, settlement)) {
|
|
651
|
+
prepareBoundSettlement = settlement;
|
|
652
|
+
prepared = await prepare();
|
|
653
|
+
selected = selectNavigatorCandidate(prepared, settlement);
|
|
654
|
+
if (selected?.next !== void 0 && !navigatorAdviceConsistentWithSettlement(selected.next, settlement)) {
|
|
655
|
+
throw new Error("Navigator advice contradicts the accepted settlement");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (selected?.next === void 0) {
|
|
659
|
+
throw new Error("Navigator prepared no machine-usable next direction");
|
|
660
|
+
}
|
|
661
|
+
const selectedRoute = selected.route;
|
|
662
|
+
const routeChanged = selectedRoute !== void 0 && !routeEqual(previousRoute, selectedRoute);
|
|
663
|
+
const command = renderPublicAkRoleCommand(selected.next);
|
|
664
|
+
report = {
|
|
665
|
+
disposition: "recommendation",
|
|
666
|
+
...routeChanged ? { route: selectedRoute } : {},
|
|
667
|
+
next: selected.next,
|
|
668
|
+
...selected.reason === void 0 ? {} : { reason: oneLine(selected.reason) },
|
|
669
|
+
...command === void 0 ? {} : { command }
|
|
670
|
+
};
|
|
671
|
+
if (selectedRoute !== void 0) {
|
|
672
|
+
previousRoute = selectedRoute;
|
|
673
|
+
session?.appendEntry(ROUTE_ENTRY, { invocationId, subjectKey, route: selectedRoute });
|
|
674
|
+
}
|
|
675
|
+
} catch (error) {
|
|
676
|
+
report = unavailable(invocationId, error);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
await routePlaybookSettlement;
|
|
680
|
+
if (routePlaybookReadFailure !== void 0) {
|
|
681
|
+
report = { ...report, routePlaybookReadFailure };
|
|
682
|
+
}
|
|
683
|
+
const event = {
|
|
684
|
+
version: 1,
|
|
685
|
+
disposition: report.disposition,
|
|
686
|
+
invocationId,
|
|
687
|
+
role: options.role,
|
|
688
|
+
phase: options.phase,
|
|
689
|
+
subjectKey,
|
|
690
|
+
...report.route === void 0 ? {} : { route: report.route },
|
|
691
|
+
...report.next === void 0 ? {} : { next: report.next },
|
|
692
|
+
...report.reason === void 0 ? {} : { reason: report.reason },
|
|
693
|
+
...report.command === void 0 ? {} : { command: report.command },
|
|
694
|
+
...report.unavailableReason === void 0 ? {} : { unavailableReason: report.unavailableReason },
|
|
695
|
+
...report.unavailableSource === void 0 ? {} : { unavailableSource: report.unavailableSource },
|
|
696
|
+
...report.unavailableCause === void 0 ? {} : { unavailableCause: report.unavailableCause },
|
|
697
|
+
...report.routePlaybookReadFailure === void 0 ? {} : { routePlaybookReadFailure: report.routePlaybookReadFailure },
|
|
698
|
+
...report.arrivalMessage === void 0 ? {} : { arrivalMessage: report.arrivalMessage }
|
|
699
|
+
};
|
|
700
|
+
if (!disposed) {
|
|
701
|
+
await options.onEvent(event, report);
|
|
702
|
+
}
|
|
703
|
+
preparation = void 0;
|
|
704
|
+
sessionReady = void 0;
|
|
705
|
+
candidates = void 0;
|
|
706
|
+
preparationFailure = void 0;
|
|
707
|
+
routePlaybookSettlement = void 0;
|
|
708
|
+
routePlaybookReadFailure = void 0;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
function createNativeNavigatorSessionFactory(defaultModelSettingPath = navigatorModelSettingPath()) {
|
|
712
|
+
const sharedModelRuntime = ModelRuntime.create({ allowModelNetwork: false });
|
|
713
|
+
return async ({ context, sessionDir, modelSettingPath, tool }) => {
|
|
714
|
+
let configured;
|
|
715
|
+
try {
|
|
716
|
+
configured = await readNavigatorModelSetting(modelSettingPath ?? defaultModelSettingPath);
|
|
717
|
+
} catch (error) {
|
|
718
|
+
throw navigatorUnavailableError("model", error);
|
|
719
|
+
}
|
|
720
|
+
let parsed;
|
|
721
|
+
try {
|
|
722
|
+
parsed = parseNavigatorModelSetting(configured);
|
|
723
|
+
} catch (error) {
|
|
724
|
+
throw navigatorUnavailableError("model", error);
|
|
725
|
+
}
|
|
726
|
+
const model = context.modelRegistry.find(parsed.provider, parsed.model);
|
|
727
|
+
const provider = context.modelRegistry.getProvider(parsed.provider);
|
|
728
|
+
if (model === void 0 || provider === void 0) throw new NavigatorUnavailableError("model", `Navigator model is unavailable: ${configured}`);
|
|
729
|
+
let auth;
|
|
730
|
+
try {
|
|
731
|
+
auth = await context.modelRegistry.getApiKeyAndHeaders(model);
|
|
732
|
+
} catch (error) {
|
|
733
|
+
throw navigatorUnavailableError("auth", error);
|
|
734
|
+
}
|
|
735
|
+
if (!auth.ok) throw new NavigatorUnavailableError("auth", auth.error);
|
|
736
|
+
try {
|
|
737
|
+
const sessionInfo = await stat(sessionDir);
|
|
738
|
+
if (!sessionInfo.isDirectory()) throw new NavigatorUnavailableError("session", `Navigator session path is not a directory: ${sessionDir}`);
|
|
739
|
+
} catch (error) {
|
|
740
|
+
if (error instanceof NavigatorUnavailableError) throw error;
|
|
741
|
+
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
|
|
742
|
+
throw navigatorUnavailableError("session", error);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
let providerFailure;
|
|
746
|
+
const assignProviderFailure = (fact) => {
|
|
747
|
+
if (fact !== void 0) providerFailure = fact;
|
|
748
|
+
};
|
|
749
|
+
const classifyProviderStreamError = (error) => {
|
|
750
|
+
if (!exactRecord(error)) {
|
|
751
|
+
assignProviderFailure(navigatorProviderFailureFromError(error));
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
assignProviderFailure(navigatorProviderFailureFromDiagnostics(error.diagnostics));
|
|
755
|
+
if (providerFailure !== void 0) return;
|
|
756
|
+
if (error.role !== "assistant") assignProviderFailure(navigatorProviderFailureFromError(error));
|
|
757
|
+
};
|
|
758
|
+
const classifyProviderResponseStatus = (status) => {
|
|
759
|
+
if (status >= 200 && status < 300) {
|
|
760
|
+
if (providerFailure?.source === "auth" || providerFailure?.source === "quota") {
|
|
761
|
+
providerFailure = void 0;
|
|
762
|
+
}
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
assignProviderFailure(navigatorProviderFailureFromStatus(status));
|
|
766
|
+
};
|
|
767
|
+
const humanProviderError = (error) => {
|
|
768
|
+
const human = { ...error };
|
|
769
|
+
delete human.statusCode;
|
|
770
|
+
delete human.code;
|
|
771
|
+
delete human.navigatorFailure;
|
|
772
|
+
return human;
|
|
773
|
+
};
|
|
774
|
+
let providerFailureEvidenceNumber = 0;
|
|
775
|
+
let providerFailureEvidence;
|
|
776
|
+
const retainProviderFailure = (error) => {
|
|
777
|
+
const id = `navigator-provider-failure-${++providerFailureEvidenceNumber}`;
|
|
778
|
+
providerFailureEvidence = { id, error };
|
|
779
|
+
return id;
|
|
780
|
+
};
|
|
781
|
+
const setupFailureMessage = (error) => ({
|
|
782
|
+
role: "assistant",
|
|
783
|
+
content: [],
|
|
784
|
+
api: "unknown",
|
|
785
|
+
provider: "unknown",
|
|
786
|
+
model: "unknown",
|
|
787
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
788
|
+
stopReason: "error",
|
|
789
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
790
|
+
navigatorFailureEvidenceId: retainProviderFailure(error),
|
|
791
|
+
timestamp: Date.now()
|
|
792
|
+
});
|
|
793
|
+
const instrumentProvider = (sourceProvider) => {
|
|
794
|
+
const instrumentStreamOptions = (options) => {
|
|
795
|
+
const record = exactRecord(options) ? options : {};
|
|
796
|
+
const previous = typeof record.onResponse === "function" ? record.onResponse : void 0;
|
|
797
|
+
return {
|
|
798
|
+
...record,
|
|
799
|
+
onResponse: async (response, model2) => {
|
|
800
|
+
classifyProviderResponseStatus(response.status);
|
|
801
|
+
await previous?.(response, model2);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
};
|
|
805
|
+
const wrapProviderStream = (source) => {
|
|
806
|
+
const wrapped = createAssistantMessageEventStream();
|
|
807
|
+
void (async () => {
|
|
808
|
+
let result;
|
|
809
|
+
let sawTerminal = false;
|
|
810
|
+
try {
|
|
811
|
+
for await (const event of source) {
|
|
812
|
+
if (event.type === "done" || event.type === "error") {
|
|
813
|
+
sawTerminal = true;
|
|
814
|
+
if (event.type === "done" && exactRecord(event.message)) {
|
|
815
|
+
assignProviderFailure(navigatorProviderFailureFromDiagnostics(event.message.diagnostics));
|
|
816
|
+
result = humanProviderError(event.message);
|
|
817
|
+
wrapped.push({ ...event, message: result });
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
if (event.type === "error" && exactRecord(event.error)) {
|
|
821
|
+
classifyProviderStreamError(event.error);
|
|
822
|
+
result = humanProviderError(event.error);
|
|
823
|
+
wrapped.push({ ...event, error: result });
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
wrapped.push(event);
|
|
828
|
+
}
|
|
829
|
+
if (sawTerminal) {
|
|
830
|
+
const terminal = await source.result();
|
|
831
|
+
if (result === void 0 && exactRecord(terminal)) result = humanProviderError(terminal);
|
|
832
|
+
else if (result === void 0) result = terminal;
|
|
833
|
+
}
|
|
834
|
+
} catch (error) {
|
|
835
|
+
classifyProviderStreamError(error);
|
|
836
|
+
if (providerFailure === void 0) providerFailure = { source: "transport", cause: "transport" };
|
|
837
|
+
if (!sawTerminal) {
|
|
838
|
+
const message = setupFailureMessage(error);
|
|
839
|
+
wrapped.push({ type: "error", reason: "error", error: message });
|
|
840
|
+
result = message;
|
|
841
|
+
sawTerminal = true;
|
|
842
|
+
}
|
|
843
|
+
} finally {
|
|
844
|
+
if (!sawTerminal) {
|
|
845
|
+
if (providerFailure === void 0) providerFailure = { source: "transport", cause: "transport" };
|
|
846
|
+
const message = setupFailureMessage(new Error("Navigator provider produced no response"));
|
|
847
|
+
wrapped.push({ type: "error", reason: "error", error: message });
|
|
848
|
+
result = message;
|
|
849
|
+
sawTerminal = true;
|
|
850
|
+
}
|
|
851
|
+
wrapped.end(result);
|
|
852
|
+
}
|
|
853
|
+
})();
|
|
854
|
+
return wrapped;
|
|
855
|
+
};
|
|
856
|
+
const invokeInstrumentedStream = (invoke) => {
|
|
857
|
+
providerFailure = void 0;
|
|
858
|
+
try {
|
|
859
|
+
return wrapProviderStream(invoke());
|
|
860
|
+
} catch (error) {
|
|
861
|
+
classifyProviderStreamError(error);
|
|
862
|
+
if (providerFailure === void 0) providerFailure = { source: "transport", cause: "transport" };
|
|
863
|
+
const wrapped = createAssistantMessageEventStream();
|
|
864
|
+
const message = setupFailureMessage(error);
|
|
865
|
+
queueMicrotask(() => {
|
|
866
|
+
wrapped.push({ type: "error", reason: "error", error: message });
|
|
867
|
+
wrapped.end(message);
|
|
868
|
+
});
|
|
869
|
+
return wrapped;
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
return {
|
|
873
|
+
...sourceProvider,
|
|
874
|
+
stream(model2, streamContext, options) {
|
|
875
|
+
const instrumented = instrumentStreamOptions(options);
|
|
876
|
+
return invokeInstrumentedStream(() => sourceProvider.stream(model2, streamContext, instrumented));
|
|
877
|
+
},
|
|
878
|
+
streamSimple(model2, streamContext, options) {
|
|
879
|
+
const instrumented = instrumentStreamOptions(options);
|
|
880
|
+
return invokeInstrumentedStream(() => sourceProvider.streamSimple(model2, streamContext, instrumented));
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
};
|
|
884
|
+
let modelRuntime;
|
|
885
|
+
try {
|
|
886
|
+
modelRuntime = await sharedModelRuntime;
|
|
887
|
+
modelRuntime.registerNativeProvider(instrumentProvider(provider));
|
|
888
|
+
} catch (error) {
|
|
889
|
+
throw navigatorUnavailableError("session", error);
|
|
890
|
+
}
|
|
891
|
+
let opened;
|
|
892
|
+
try {
|
|
893
|
+
opened = await openInProcessAgentSession({
|
|
894
|
+
cwd: context.cwd,
|
|
895
|
+
model,
|
|
896
|
+
modelRuntime,
|
|
897
|
+
thinkingLevel: parsed.thinkingLevel,
|
|
898
|
+
sessionManager: SessionManager.continueRecent(context.cwd, sessionDir),
|
|
899
|
+
noTools: "all",
|
|
900
|
+
tools: [NAVIGATOR_PREPARE_TOOL_NAME],
|
|
901
|
+
customTools: [tool]
|
|
902
|
+
});
|
|
903
|
+
} catch (error) {
|
|
904
|
+
throw navigatorUnavailableError("session", error);
|
|
905
|
+
}
|
|
906
|
+
if (opened.session.thinkingLevel !== parsed.thinkingLevel) {
|
|
907
|
+
opened.dispose();
|
|
908
|
+
throw new NavigatorUnavailableError("thinking", `Navigator thinking level ${parsed.thinkingLevel} is unavailable for ${configured}`);
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
prompt: async (text) => {
|
|
912
|
+
try {
|
|
913
|
+
await opened.session.prompt(text);
|
|
914
|
+
} catch (error) {
|
|
915
|
+
throw navigatorUnavailableError("transport", error);
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
providerFailure: () => providerFailure,
|
|
919
|
+
appendEntry: (customType, data) => {
|
|
920
|
+
opened.session.sessionManager.appendCustomEntry(customType, data);
|
|
921
|
+
},
|
|
922
|
+
entries: () => opened.session.sessionManager.getEntries(),
|
|
923
|
+
setModel: async (next, thinkingLevel) => {
|
|
924
|
+
let nextParsed;
|
|
925
|
+
try {
|
|
926
|
+
nextParsed = parseNavigatorModelSetting(next);
|
|
927
|
+
} catch (error) {
|
|
928
|
+
throw navigatorUnavailableError("model", error);
|
|
929
|
+
}
|
|
930
|
+
const nextModel = context.modelRegistry.find(nextParsed.provider, nextParsed.model);
|
|
931
|
+
const nextProvider = context.modelRegistry.getProvider(nextParsed.provider);
|
|
932
|
+
if (nextModel === void 0 || nextProvider === void 0) throw new NavigatorUnavailableError("model", `Navigator model is unavailable: ${next}`);
|
|
933
|
+
let nextAuth;
|
|
934
|
+
try {
|
|
935
|
+
nextAuth = await context.modelRegistry.getApiKeyAndHeaders(nextModel);
|
|
936
|
+
} catch (error) {
|
|
937
|
+
throw navigatorUnavailableError("auth", error);
|
|
938
|
+
}
|
|
939
|
+
if (!nextAuth.ok) throw new NavigatorUnavailableError("auth", nextAuth.error);
|
|
940
|
+
try {
|
|
941
|
+
modelRuntime.registerNativeProvider(instrumentProvider(nextProvider));
|
|
942
|
+
await opened.session.setModel(nextModel);
|
|
943
|
+
opened.session.setThinkingLevel(thinkingLevel);
|
|
944
|
+
} catch (error) {
|
|
945
|
+
throw navigatorUnavailableError("session", error);
|
|
946
|
+
}
|
|
947
|
+
if (opened.session.thinkingLevel !== nextParsed.thinkingLevel || opened.session.thinkingLevel !== thinkingLevel) {
|
|
948
|
+
throw new NavigatorUnavailableError("thinking", `Navigator thinking level ${thinkingLevel} is unavailable for ${next}`);
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
getThinkingLevel: () => opened.session.thinkingLevel,
|
|
952
|
+
dispose: () => opened.dispose()
|
|
953
|
+
};
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
function registerNavigatorModelCommand(pi, path = navigatorModelSettingPath()) {
|
|
957
|
+
pi.registerCommand("navigator-model", {
|
|
958
|
+
description: "Set the persistent Navigator model (provider/model[:max]).",
|
|
959
|
+
handler: async (args) => {
|
|
960
|
+
await writeNavigatorModelSetting(args.trim(), path);
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
function navigatorSessionDirectory(context, subjectKey) {
|
|
965
|
+
const current = context.sessionManager.getSessionDir();
|
|
966
|
+
const key = subjectKey ?? subjectPath(current, context.cwd);
|
|
967
|
+
return subjectDirectory(context.cwd, key);
|
|
968
|
+
}
|
|
969
|
+
export {
|
|
970
|
+
NAVIGATOR_DEFAULT_MODEL,
|
|
971
|
+
NAVIGATOR_EVENT_TYPE,
|
|
972
|
+
NAVIGATOR_PREPARE_TOOL_NAME,
|
|
973
|
+
NAVIGATOR_TARGETS,
|
|
974
|
+
NavigatorUnavailableError,
|
|
975
|
+
createNativeNavigatorSessionFactory,
|
|
976
|
+
createNavigatorAttendance,
|
|
977
|
+
createNavigatorPrepareTool,
|
|
978
|
+
decorateSettlementWithNavigation,
|
|
979
|
+
formatNavigatorReport,
|
|
980
|
+
navigatorAdviceConsistentWithSettlement,
|
|
981
|
+
navigatorModelSettingPath,
|
|
982
|
+
navigatorProviderFailure,
|
|
983
|
+
navigatorProviderFailureFromError,
|
|
984
|
+
navigatorSessionDirectory,
|
|
985
|
+
navigatorSubjectKey,
|
|
986
|
+
navigatorSubjectKeyForInput,
|
|
987
|
+
navigatorUnavailableError,
|
|
988
|
+
parseNavigatorModelSetting,
|
|
989
|
+
readNavigatorModelSetting,
|
|
990
|
+
registerNavigatorModelCommand,
|
|
991
|
+
selectNavigatorCandidate,
|
|
992
|
+
settlementNavigationFromEvent,
|
|
993
|
+
subjectPath,
|
|
994
|
+
writeNavigatorModelSetting
|
|
995
|
+
};
|