@code-yeongyu/senpi 2026.11.2-3 → 2026.11.3-1
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/CHANGELOG.md +28 -0
- package/dist/bundle/chunks/{anthropic-messages-WUPLDYD6.js → anthropic-messages-AFWQB3KN.js} +1 -1
- package/dist/bundle/chunks/{args-AOI4NEA6.js → args-O3WS4WCO.js} +1 -1
- package/dist/bundle/chunks/{chunk-O4GRBX4R.js → chunk-3WJ2DE2G.js} +1 -1
- package/dist/bundle/chunks/{chunk-LMIETUPG.js → chunk-4BF4FLT6.js} +1 -1
- package/dist/bundle/chunks/{chunk-T5ZJ2Q4O.js → chunk-4SENPCEA.js} +1 -1
- package/dist/bundle/chunks/chunk-5DZD623T.js +448 -0
- package/dist/bundle/chunks/{chunk-TXOR5BQL.js → chunk-6BSMXZKQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-VRWJJMHO.js → chunk-7565XQAU.js} +1 -1
- package/dist/bundle/chunks/{chunk-IWM5QRAE.js → chunk-7KLEFHSU.js} +1 -1
- package/dist/bundle/chunks/{chunk-FO56LSUK.js → chunk-BNIZP4OS.js} +1 -1
- package/dist/bundle/chunks/{chunk-L3V65XW7.js → chunk-CJWSQ6CK.js} +1 -1
- package/dist/bundle/chunks/{chunk-QLTQ3UUI.js → chunk-DAPBNRN5.js} +1 -1
- package/dist/bundle/chunks/{chunk-GIY7PGOH.js → chunk-DPBPO5OU.js} +1 -1
- package/dist/bundle/chunks/chunk-ESQBKTNG.js +2 -0
- package/dist/bundle/chunks/{chunk-N4TSAHRL.js → chunk-EVTTLPIY.js} +1 -1
- package/dist/bundle/chunks/{chunk-NYXXKS6D.js → chunk-F4OHTL2K.js} +3 -2
- package/dist/bundle/chunks/{chunk-TVMW2SUP.js → chunk-FJ2UCBOA.js} +2 -2
- package/dist/bundle/chunks/{chunk-KVPRQ5KN.js → chunk-FLM6GZPT.js} +1 -1
- package/dist/bundle/chunks/{chunk-P4AT7SBE.js → chunk-HBCNDC53.js} +1 -1
- package/dist/bundle/chunks/chunk-MOH5HOHX.js +2 -0
- package/dist/bundle/chunks/{chunk-7FUO655J.js → chunk-MOOFLKLI.js} +1 -1
- package/dist/bundle/chunks/{chunk-IHOQR7TU.js → chunk-PX7FF5LE.js} +1 -1
- package/dist/bundle/chunks/{chunk-QAM6AXA2.js → chunk-QTQ3ES2S.js} +12 -9
- package/dist/bundle/chunks/{chunk-FJSJUVQQ.js → chunk-TOOB6OLG.js} +3 -3
- package/dist/bundle/chunks/{chunk-662SCMTH.js → chunk-VPDQ6MOL.js} +1 -1
- package/dist/bundle/chunks/{chunk-BW4YXS7X.js → chunk-WCRNJYHO.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZSVWKOAJ.js → chunk-ZNLCKKF6.js} +170 -226
- package/dist/bundle/chunks/{cli-main-534A3WSC.js → cli-main-XM5FWY3Z.js} +1 -1
- package/dist/bundle/chunks/{credential-accounts-OAK2E5O2.js → credential-accounts-YZYSKA7X.js} +1 -1
- package/dist/bundle/chunks/{health-write-EB4CPHXN.js → health-write-45CX64T2.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-U2PSNNWO.js → help-fast-path-3EDGRKQM.js} +1 -1
- package/dist/bundle/chunks/{host-command-WJIMRBGN.js → host-command-PZ4VYQIW.js} +1 -1
- package/dist/bundle/chunks/{host-session-command-PWVPQ2OV.js → host-session-command-OJFARE5Q.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-NPHFDPGH.js → interactive-mode-7JSJVVIS.js} +1 -1
- package/dist/bundle/chunks/{login-health-7G2DZVOV.js → login-health-YOPTYRTU.js} +1 -1
- package/dist/bundle/chunks/{main-I6FJAFUP.js → main-3YGJ2O4I.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-7E26R5JF.js → multi-session-host-N2RQ7JSZ.js} +4 -4
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-VNBMMIL3.js → openai-codex-responses-YTWLG4OL.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-JLR32APM.js → openai-completions-TIFDYHZL.js} +1 -1
- package/dist/bundle/chunks/{openai-images-LEBNERSM.js → openai-images-OAEMY4RG.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-JCDUNMHA.js → openai-responses-L35NIG5Y.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-CBSDV36M.js → package-manager-cli-JPNA27E5.js} +1 -1
- package/dist/bundle/chunks/{role-LP6LVNCY.js → role-45Y7PQFC.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-ZDCNHIBE.js → rotation-stream-WXWJKJZN.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-GBBTN2WP.js → rpc-mode-Z7MN2ZWA.js} +1 -1
- package/dist/bundle/chunks/{run-attached-tui-PVLUHHJX.js → run-attached-tui-TI6MELEI.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-W45NYTTK.js → schedule-command-OZ5ESMIT.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-LFLUNALC.js → session-control-endpoint-5YKBYJOO.js} +1 -1
- package/dist/bundle/chunks/{session-picker-OZUINLD7.js → session-picker-CMRV72VA.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +324 -376
- package/dist/bundle/chunks/{state-store-SZARKD36.js → state-store-Q47AYMRI.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session.d.ts +8 -0
- package/dist/core/agent-session.js +68 -60
- package/dist/core/credential-pool/classify.d.ts +3 -2
- package/dist/core/credential-pool/classify.js +10 -3
- package/dist/core/dynamic-prompt/build.d.ts +2 -1
- package/dist/core/dynamic-prompt/build.js +1 -2
- package/dist/core/dynamic-prompt/handoff.d.ts +1 -1
- package/dist/core/dynamic-prompt/handoff.js +9 -9
- package/dist/core/dynamic-prompt/identity.js +1 -1
- package/dist/core/dynamic-prompt/intent-gate.d.ts +1 -1
- package/dist/core/dynamic-prompt/intent-gate.js +8 -8
- package/dist/core/dynamic-prompt/policies.d.ts +1 -1
- package/dist/core/dynamic-prompt/policies.js +5 -7
- package/dist/core/dynamic-prompt/style.js +5 -5
- package/dist/core/dynamic-prompt/tool-section.d.ts +5 -0
- package/dist/core/dynamic-prompt/tool-section.js +8 -6
- package/dist/core/dynamic-prompt/verification.d.ts +6 -6
- package/dist/core/dynamic-prompt/verification.js +12 -12
- package/dist/core/dynamic-prompt/working-task.d.ts +1 -1
- package/dist/core/dynamic-prompt/working-task.js +3 -3
- package/dist/core/dynamic-prompt/workstation.js +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts +13 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +64 -2
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +5 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.d.ts +7 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.js +28 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +2 -0
- package/dist/core/extensions/builtin/bash-timeout/index.d.ts +1 -1
- package/dist/core/extensions/builtin/bash-timeout/index.js +3 -28
- package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +0 -11
- package/dist/core/extensions/builtin/bash-timeout/timeout.js +0 -11
- package/dist/core/extensions/builtin/imagegen/index.d.ts +0 -1
- package/dist/core/extensions/builtin/imagegen/index.js +0 -11
- package/dist/core/extensions/builtin/prompt-preset/execution-tooling.d.ts +5 -5
- package/dist/core/extensions/builtin/prompt-preset/execution-tooling.js +5 -5
- package/dist/core/extensions/builtin/prompt-preset/glm-5.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5.js +1 -1
- package/dist/core/extensions/builtin/terminal/extension.js +8 -1
- package/dist/core/extensions/builtin/terminal/notify.js +9 -3
- package/dist/core/extensions/builtin/terminal/prompt.d.ts +7 -1
- package/dist/core/extensions/builtin/terminal/prompt.js +27 -60
- package/dist/core/extensions/builtin/terminal/tools/bash.js +10 -2
- package/dist/core/extensions/builtin/todotools/normalize.d.ts +20 -3
- package/dist/core/extensions/builtin/todotools/normalize.js +251 -5
- package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
- package/dist/core/extensions/builtin/todotools/prompt.js +5 -5
- package/dist/core/extensions/builtin/todotools/tools/todo.js +9 -8
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +0 -5
- package/dist/core/extensions/builtin/websearch/index.js +9 -4
- package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts +2 -0
- package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -1
- package/dist/core/model-runtime.js +1 -1
- package/dist/core/provider-failure.d.ts +6 -0
- package/dist/core/provider-failure.js +6 -2
- package/dist/core/retry-fallback/exhaustion.d.ts +18 -0
- package/dist/core/retry-fallback/exhaustion.js +20 -0
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/tools/bash.d.ts +3 -1
- package/dist/core/tools/bash.js +14 -4
- package/dist/core/tools/edit.d.ts +1 -1
- package/dist/core/tools/edit.js +1 -6
- package/dist/core/tools/grep/index.js +2 -3
- package/dist/core/tools/powershell.d.ts +1 -1
- package/dist/core/tools/powershell.js +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/write.d.ts +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/engine-trust/shell-trust.d.ts +36 -0
- package/dist/engine-trust/shell-trust.js +44 -0
- package/dist/engine-trust/transport-failure.d.ts +12 -0
- package/dist/engine-trust/transport-failure.js +48 -0
- package/dist/modes/interactive/interactive-mode.js +9 -3
- package/dist/modes/print-mode.js +2 -1
- package/dist/modes/rpc/compact-catalog-families.d.ts +5 -2
- package/dist/modes/rpc/compact-catalog-families.js +5 -2
- package/dist/modes/rpc/compact-catalog-registry.d.ts +9 -1
- package/dist/modes/rpc/compact-catalog-registry.js +9 -2
- package/dist/modes/rpc/compact-recovery-manifest-kinds.d.ts +17 -0
- package/dist/modes/rpc/compact-recovery-manifest-kinds.js +21 -0
- package/dist/modes/rpc/compact-recovery-manifest-shape.d.ts +7 -0
- package/dist/modes/rpc/compact-recovery-manifest.js +11 -3
- package/dist/modes/rpc/compact-socket-commands.js +6 -0
- package/dist/modes/rpc/connection-handler.js +21 -5
- package/dist/modes/rpc/connection-question-bridge.d.ts +3 -1
- package/dist/modes/rpc/connection-question-bridge.js +4 -1
- package/dist/modes/rpc/connection-roles.d.ts +8 -0
- package/dist/modes/rpc/connection-roles.js +18 -0
- package/dist/modes/rpc/method-classes-schema-session.d.ts +4 -0
- package/dist/modes/rpc/method-classes-schema-session.js +1 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +4 -0
- package/dist/modes/rpc/protocol-identity.js +2 -0
- package/dist/modes/rpc/remote-origin.d.ts +31 -0
- package/dist/modes/rpc/remote-origin.js +58 -0
- package/dist/modes/rpc/rpc-protocol-info-types.d.ts +8 -0
- package/dist/modes/rpc/rpc-question-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-question-types.js +0 -3
- package/dist/modes/rpc/rpc-session-command-types.d.ts +3 -0
- package/dist/modes/rpc/session-registry.js +12 -3
- package/dist/modes/rpc/session-worker-client.js +2 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +3 -0
- package/dist/modes/rpc/session-worker.js +2 -0
- package/docs/engine-socket/fixtures/admission-routes/c-baseline.json +3 -3
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/admission-routes/i-reset-stream.json +3 -3
- package/docs/engine-socket/fixtures/recovery-manifest/index.json +32 -0
- package/docs/engine-socket/fixtures/recovery-manifest/one-partial-family.json +118 -0
- package/docs/rpc.md +93 -3
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-7UC4W2T2.js +0 -2
- package/dist/bundle/chunks/chunk-R23WXN4L.js +0 -448
- package/dist/bundle/chunks/chunk-W5NLCRB3.js +0 -2
|
@@ -30,9 +30,8 @@ const grepSchema = Type.Object({
|
|
|
30
30
|
});
|
|
31
31
|
export const grepToolSystemPromptContribution = {
|
|
32
32
|
snippet: "Search file contents (regex/literal) across paths with structured results; respects .gitignore",
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
],
|
|
33
|
+
// The eval-only grep guideline (system-prompt.ts getEvalOnlyGrepGuideline) carries the pagination rule once.
|
|
34
|
+
guidelines: [],
|
|
36
35
|
};
|
|
37
36
|
async function pathStat(path) {
|
|
38
37
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type BashOperations, type BashSpawnContext, type BashSpawnHook, type BashToolDetails, type BashToolInput, type BashToolOptions, type createBashTool, createShellToolDefinition } from "./bash.ts";
|
|
2
2
|
export declare const powershellToolSystemPromptContribution: {
|
|
3
3
|
readonly snippet: "Execute PowerShell commands";
|
|
4
|
-
readonly guidelines: readonly ["
|
|
4
|
+
readonly guidelines: readonly ["PI_* env vars = current model + session details."];
|
|
5
5
|
};
|
|
6
6
|
export type PowerShellOperations = BashOperations;
|
|
7
7
|
export type PowerShellSpawnContext = BashSpawnContext;
|
|
@@ -4,7 +4,7 @@ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
|
4
4
|
const UTF8_OUTPUT_PREFIX = "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
|
|
5
5
|
export const powershellToolSystemPromptContribution = {
|
|
6
6
|
snippet: "Execute PowerShell commands",
|
|
7
|
-
guidelines: ["
|
|
7
|
+
guidelines: ["PI_* env vars = current model + session details."],
|
|
8
8
|
};
|
|
9
9
|
export function createLocalPowerShellOperations() {
|
|
10
10
|
const operations = createLocalShellOperations("PowerShell", getPowerShellConfig);
|
|
@@ -11,7 +11,7 @@ declare const readSchema: Type.TObject<{
|
|
|
11
11
|
}>;
|
|
12
12
|
export declare const readToolSystemPromptContribution: {
|
|
13
13
|
readonly snippet: "Read file contents";
|
|
14
|
-
readonly guidelines: readonly ["
|
|
14
|
+
readonly guidelines: readonly ["Files: read, not cat/sed."];
|
|
15
15
|
};
|
|
16
16
|
export type ReadToolInput = Static<typeof readSchema>;
|
|
17
17
|
export interface ReadToolDetails {
|
package/dist/core/tools/read.js
CHANGED
|
@@ -17,7 +17,7 @@ const readSchema = Type.Object({
|
|
|
17
17
|
});
|
|
18
18
|
export const readToolSystemPromptContribution = {
|
|
19
19
|
snippet: "Read file contents",
|
|
20
|
-
guidelines: ["
|
|
20
|
+
guidelines: ["Files: read, not cat/sed."],
|
|
21
21
|
};
|
|
22
22
|
const LOCAL_URI_SCHEME = /^local:\/\//i;
|
|
23
23
|
const LOCAL_URI_GUIDANCE = "local:// URIs resolve only inside eval cells via the kernel read()/write() helpers; the read tool takes filesystem paths. Re-read this with the eval read() helper, or retry with the plain absolute file path.";
|
|
@@ -8,7 +8,7 @@ declare const writeSchema: Type.TObject<{
|
|
|
8
8
|
}>;
|
|
9
9
|
export declare const writeToolSystemPromptContribution: {
|
|
10
10
|
readonly snippet: "Create or overwrite files";
|
|
11
|
-
readonly guidelines: readonly ["
|
|
11
|
+
readonly guidelines: readonly ["write only for new files or full rewrites."];
|
|
12
12
|
};
|
|
13
13
|
export type WriteToolInput = Static<typeof writeSchema>;
|
|
14
14
|
/**
|
package/dist/core/tools/write.js
CHANGED
|
@@ -13,7 +13,7 @@ const writeSchema = Type.Object({
|
|
|
13
13
|
});
|
|
14
14
|
export const writeToolSystemPromptContribution = {
|
|
15
15
|
snippet: "Create or overwrite files",
|
|
16
|
-
guidelines: ["
|
|
16
|
+
guidelines: ["write only for new files or full rewrites."],
|
|
17
17
|
};
|
|
18
18
|
const defaultWriteOperations = {
|
|
19
19
|
writeFile: (path, content) => fsWriteFile(path, content, "utf-8"),
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trust annotation on agent-shell results (omo#10762, design r13 6.7). Under a fallback generation a
|
|
3
|
+
* command that exits non-zero carries a trusted status taken from the adopted record and, only when its
|
|
4
|
+
* output looks like a certificate verification error, an untrusted hint naming the matched catalog pattern.
|
|
5
|
+
* The output never supplies a reason or an action: any command can print any text, including a forged
|
|
6
|
+
* Bun footer or trust line (design M16). Like `adopted.ts`, this module does not load the marker parser.
|
|
7
|
+
*/
|
|
8
|
+
import { type EngineTrustActionId } from "./actions.ts";
|
|
9
|
+
import type { ENGINE_TRUST_FALLBACK_REASONS } from "./marker.ts";
|
|
10
|
+
/** Catalog order decides which entry a hint names when several match. */
|
|
11
|
+
declare const SHELL_TRUST_PATTERNS: readonly [readonly ["UNABLE_TO_GET_ISSUER_CERT_LOCALLY", RegExp], readonly ["UNABLE_TO_GET_ISSUER_CERT", RegExp], readonly ["UNABLE_TO_VERIFY_LEAF_SIGNATURE", RegExp], readonly ["SELF_SIGNED_CERT_IN_CHAIN", RegExp], readonly ["DEPTH_ZERO_SELF_SIGNED_CERT", RegExp], readonly ["CERT_UNTRUSTED", RegExp], readonly ["unable-to-verify-the-first-certificate", RegExp], readonly ["unable-to-get-local-issuer-certificate", RegExp], readonly ["unable-to-get-issuer-certificate", RegExp], readonly ["self-signed-certificate-in-certificate-chain", RegExp], readonly ["self-signed-certificate", RegExp], readonly ["certificate-not-trusted", RegExp]];
|
|
12
|
+
export type ShellTrustPatternId = (typeof SHELL_TRUST_PATTERNS)[number][0];
|
|
13
|
+
export type ShellTrust = {
|
|
14
|
+
readonly status: {
|
|
15
|
+
readonly code: "trust-import-degraded";
|
|
16
|
+
readonly reason: (typeof ENGINE_TRUST_FALLBACK_REASONS)[number];
|
|
17
|
+
readonly action: EngineTrustActionId;
|
|
18
|
+
};
|
|
19
|
+
readonly hint?: {
|
|
20
|
+
readonly code: "tls-verify-text-in-output";
|
|
21
|
+
readonly heuristic: true;
|
|
22
|
+
readonly pattern: ShellTrustPatternId;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type ShellTrustAnnotation = {
|
|
26
|
+
readonly trust: ShellTrust;
|
|
27
|
+
/** The one fixed line appended for the model, only with a hint; it never echoes output. */
|
|
28
|
+
readonly text: string | undefined;
|
|
29
|
+
};
|
|
30
|
+
/** Nothing without an adopted fallback generation, on exit 0, or for a command that has no exit code. */
|
|
31
|
+
export declare function annotateShellTrust({ exitCode, output, }: {
|
|
32
|
+
readonly exitCode: number | null;
|
|
33
|
+
readonly output: string;
|
|
34
|
+
}): ShellTrustAnnotation | undefined;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=shell-trust.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trust annotation on agent-shell results (omo#10762, design r13 6.7). Under a fallback generation a
|
|
3
|
+
* command that exits non-zero carries a trusted status taken from the adopted record and, only when its
|
|
4
|
+
* output looks like a certificate verification error, an untrusted hint naming the matched catalog pattern.
|
|
5
|
+
* The output never supplies a reason or an action: any command can print any text, including a forged
|
|
6
|
+
* Bun footer or trust line (design M16). Like `adopted.ts`, this module does not load the marker parser.
|
|
7
|
+
*/
|
|
8
|
+
import { engineTrustAction } from "./actions.js";
|
|
9
|
+
import { adoptedEngineTrust } from "./adopted.js";
|
|
10
|
+
/** A verification code (design 6.6) as a whole token, whatever quotes surround it. */
|
|
11
|
+
const token = (code) => new RegExp(`(?<![A-Za-z0-9_])${code}(?![A-Za-z0-9_])`, "u");
|
|
12
|
+
/** Catalog order decides which entry a hint names when several match. */
|
|
13
|
+
const SHELL_TRUST_PATTERNS = [
|
|
14
|
+
["UNABLE_TO_GET_ISSUER_CERT_LOCALLY", token("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")],
|
|
15
|
+
["UNABLE_TO_GET_ISSUER_CERT", token("UNABLE_TO_GET_ISSUER_CERT")],
|
|
16
|
+
["UNABLE_TO_VERIFY_LEAF_SIGNATURE", token("UNABLE_TO_VERIFY_LEAF_SIGNATURE")],
|
|
17
|
+
["SELF_SIGNED_CERT_IN_CHAIN", token("SELF_SIGNED_CERT_IN_CHAIN")],
|
|
18
|
+
["DEPTH_ZERO_SELF_SIGNED_CERT", token("DEPTH_ZERO_SELF_SIGNED_CERT")],
|
|
19
|
+
["CERT_UNTRUSTED", token("CERT_UNTRUSTED")],
|
|
20
|
+
["unable-to-verify-the-first-certificate", /unable to verify the first certificate/iu],
|
|
21
|
+
["unable-to-get-local-issuer-certificate", /unable to get local issuer certificate/iu],
|
|
22
|
+
["unable-to-get-issuer-certificate", /unable to get issuer certificate/iu],
|
|
23
|
+
["self-signed-certificate-in-certificate-chain", /self[- ]signed certificate in certificate chain/iu],
|
|
24
|
+
["self-signed-certificate", /self[- ]signed certificate/iu],
|
|
25
|
+
["certificate-not-trusted", /certificate not trusted/iu],
|
|
26
|
+
];
|
|
27
|
+
/** Nothing without an adopted fallback generation, on exit 0, or for a command that has no exit code. */
|
|
28
|
+
export function annotateShellTrust({ exitCode, output, }) {
|
|
29
|
+
const marker = adoptedEngineTrust();
|
|
30
|
+
if (marker?.automatic !== "fallback" || marker.fallbackReason === null || exitCode === null || exitCode === 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const reason = marker.fallbackReason;
|
|
34
|
+
const action = engineTrustAction(reason);
|
|
35
|
+
const status = { code: "trust-import-degraded", reason, action: action.id };
|
|
36
|
+
const pattern = SHELL_TRUST_PATTERNS.find(([, matcher]) => matcher.test(output))?.[0];
|
|
37
|
+
if (pattern === undefined)
|
|
38
|
+
return { trust: { status }, text: undefined };
|
|
39
|
+
return {
|
|
40
|
+
trust: { status, hint: { code: "tls-verify-text-in-output", heuristic: true, pattern } },
|
|
41
|
+
text: `omo: certificate import is degraded (${reason}), so some TLS connections may fail. This command's output contains text that looks like a certificate verification error; omo has not confirmed the cause. To diagnose: ${action.text}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=shell-trust.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ProviderDiagnostic } from "@earendil-works/pi-ai";
|
|
2
|
+
import { type EngineTrustActionId } from "./actions.ts";
|
|
3
|
+
import type { ENGINE_TRUST_FALLBACK_REASONS } from "./marker.ts";
|
|
4
|
+
type FallbackReason = (typeof ENGINE_TRUST_FALLBACK_REASONS)[number];
|
|
5
|
+
export interface TransportTrustFailure {
|
|
6
|
+
readonly code: "trust-tls-failed-under-fallback";
|
|
7
|
+
readonly reason: FallbackReason;
|
|
8
|
+
readonly action: EngineTrustActionId;
|
|
9
|
+
}
|
|
10
|
+
export declare function transportTrustFailure(diagnostic: ProviderDiagnostic | undefined): TransportTrustFailure | undefined;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=transport-failure.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `trust` object a provider failure carries when the request failed TLS chain verification while
|
|
3
|
+
* this engine runs on a fallback trust generation (omo#10762, design r13 6.6; senpi#5244). The code
|
|
4
|
+
* comes only from the adapter's structured transport diagnostic, which reads the native error's
|
|
5
|
+
* `code`, never message text. The object and its diagnostics record name no host, path or certificate.
|
|
6
|
+
*/
|
|
7
|
+
import { appendFile } from "node:fs/promises";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { isTlsChainVerificationCode } from "@earendil-works/pi-ai";
|
|
10
|
+
import { engineTrustAction } from "./actions.js";
|
|
11
|
+
import { adoptedEngineTrust } from "./adopted.js";
|
|
12
|
+
/** Reasons this process already wrote a record for: one record per process and reason. */
|
|
13
|
+
const recordedReasons = new Set();
|
|
14
|
+
export function transportTrustFailure(diagnostic) {
|
|
15
|
+
if (diagnostic?.evidence !== "structured_transport" || diagnostic.code === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (!isTlsChainVerificationCode(diagnostic.code))
|
|
18
|
+
return undefined;
|
|
19
|
+
const trust = adoptedEngineTrust();
|
|
20
|
+
if (trust?.automatic !== "fallback" || trust.fallbackReason === null)
|
|
21
|
+
return undefined;
|
|
22
|
+
const reason = trust.fallbackReason;
|
|
23
|
+
if (!recordedReasons.has(reason)) {
|
|
24
|
+
recordedReasons.add(reason);
|
|
25
|
+
appendDiagnosticsRecord(trust.file, {
|
|
26
|
+
v: 1,
|
|
27
|
+
at: new Date().toISOString(),
|
|
28
|
+
pid: process.pid,
|
|
29
|
+
generation: trust.sha256,
|
|
30
|
+
codes: ["trust-tls-failed-under-fallback", reason],
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return { code: "trust-tls-failed-under-fallback", reason, action: engineTrustAction(reason).id };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* One line, in one append, to `diagnostics.jsonl` beside the generation file (design 5.3). The append
|
|
37
|
+
* is asynchronous because this runs on the RPC session path, which takes no blocking filesystem call
|
|
38
|
+
* (no-sync-in-session-path). A record that cannot be written costs only the record: the failure still
|
|
39
|
+
* carries its `trust` object.
|
|
40
|
+
*/
|
|
41
|
+
function appendDiagnosticsRecord(generationFile, record) {
|
|
42
|
+
appendFile(join(dirname(generationFile), "diagnostics.jsonl"), `${JSON.stringify(record)}\n`, {
|
|
43
|
+
mode: 0o600,
|
|
44
|
+
}).catch(() => {
|
|
45
|
+
// The trust directory may be gone or read-only; the record is diagnostic only.
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=transport-failure.js.map
|
|
@@ -46,6 +46,7 @@ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScop
|
|
|
46
46
|
import { CredentialSynchronizationError } from "../../core/model-runtime.js";
|
|
47
47
|
import { formatProviderFailure } from "../../core/provider-failure.js";
|
|
48
48
|
import { failureAlreadyDescribed, headNoticeShownElsewhere } from "./provider-error-description.js";
|
|
49
|
+
import { describeFallbackExhaustion } from "../../core/retry-fallback/exhaustion.js";
|
|
49
50
|
import { usageLimitCause } from "../../core/retry-fallback/usage-limit.js";
|
|
50
51
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
51
52
|
import { createSessionLogger } from "../../core/session-log.js";
|
|
@@ -4864,19 +4865,24 @@ export class InteractiveMode {
|
|
|
4864
4865
|
});
|
|
4865
4866
|
this.setExtensionStatus(FALLBACK_STATUS_KEY, undefined);
|
|
4866
4867
|
break;
|
|
4867
|
-
case "retry_fallback_exhausted":
|
|
4868
|
-
|
|
4868
|
+
case "retry_fallback_exhausted": {
|
|
4869
|
+
// A walk that started on another failure must lead with it, not the last rung's (senpi#4084).
|
|
4870
|
+
const startedElsewhere = (event.failures?.length ?? 0) > 1;
|
|
4871
|
+
if (isRetryableProviderError(event.lastError) && !startedElsewhere) {
|
|
4869
4872
|
this.getProviderErrors().finish(event.lastError);
|
|
4870
4873
|
this.setExtensionStatus(FALLBACK_STATUS_KEY, undefined);
|
|
4871
4874
|
break;
|
|
4872
4875
|
}
|
|
4876
|
+
if (isRetryableProviderError(event.lastError))
|
|
4877
|
+
this.getProviderErrors().clear();
|
|
4873
4878
|
this.showNoticeBox({
|
|
4874
4879
|
title: `✕ Fallback chain exhausted · ${event.chainKey}`,
|
|
4875
4880
|
tone: "error",
|
|
4876
|
-
why: event
|
|
4881
|
+
why: describeFallbackExhaustion(event),
|
|
4877
4882
|
});
|
|
4878
4883
|
this.setExtensionStatus(FALLBACK_STATUS_KEY, undefined);
|
|
4879
4884
|
break;
|
|
4885
|
+
}
|
|
4880
4886
|
case "server_fallback_aborted":
|
|
4881
4887
|
this.showNoticeBox({
|
|
4882
4888
|
title: `⚠ Server fallback aborted · ${event.from} → ${event.to}`,
|
package/dist/modes/print-mode.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { describeProviderFailureForUser, stripTurnRetrySuppressionPrefix, } from "@earendil-works/pi-ai";
|
|
9
9
|
import { flushRawStdout, waitForRawStdoutBackpressure, writeRawStdout } from "../core/output-guard.js";
|
|
10
|
+
import { describeFallbackExhaustion } from "../core/retry-fallback/exhaustion.js";
|
|
10
11
|
import { usageLimitCause, usageLimitScope } from "../core/retry-fallback/usage-limit.js";
|
|
11
12
|
import { killTrackedDetachedChildren } from "../utils/shell.js";
|
|
12
13
|
import { toJsonEvent } from "./json-event.js";
|
|
@@ -107,7 +108,7 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
107
108
|
console.error(`Model fallback: ${event.from} -> ${event.to} (${usageLimitCause(event.from, event.limit) ?? event.reason})`);
|
|
108
109
|
}
|
|
109
110
|
else if (event.type === "retry_fallback_exhausted") {
|
|
110
|
-
console.error(`Model fallback exhausted: ${event.chainKey} (${event.
|
|
111
|
+
console.error(`Model fallback exhausted: ${event.chainKey} (${describeFallbackExhaustion(event).replaceAll("\n", "; ")})`);
|
|
111
112
|
}
|
|
112
113
|
else if (event.type === "retry_fallback_reverted") {
|
|
113
114
|
const cause = event.cause === "fallback-unusable" ? ` (${event.from} cannot serve right now)` : "";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FamilyRegistry } from "./compact-catalog-registry.ts";
|
|
1
2
|
import type { CompactContentStore } from "./compact-content-store.ts";
|
|
2
3
|
import type { CatalogComponent } from "./compact-recovery-catalog.ts";
|
|
3
4
|
import type { SettledReader } from "./compact-settled-messages.ts";
|
|
@@ -16,8 +17,10 @@ interface CatalogCut {
|
|
|
16
17
|
* the members it enumerated and never an explicit empty, so a reader can tell "no members" from "not enumerated"
|
|
17
18
|
* (RULING-60 Q1, RULING-61 Q1). Members stream one at a time: a value goes through `walk` into bounded leaves, a
|
|
18
19
|
* collection through `rows`, and each component's leaves are released once the catalog has placed it. The
|
|
19
|
-
* completeness gate runs last: a complete producer that emitted nothing refuses the whole catalog (X03).
|
|
20
|
+
* completeness gate runs last: a complete producer that emitted nothing refuses the whole catalog (X03). Its return
|
|
21
|
+
* value is the registry it emitted as `families/families`, the one source the manifest copies `requiredKinds` from
|
|
22
|
+
* (RULING-128).
|
|
20
23
|
*/
|
|
21
|
-
export declare function checkpointComponents(cut: CatalogCut, valid: () => void): AsyncGenerator<CatalogComponent>;
|
|
24
|
+
export declare function checkpointComponents(cut: CatalogCut, valid: () => void): AsyncGenerator<CatalogComponent, FamilyRegistry>;
|
|
22
25
|
export {};
|
|
23
26
|
//# sourceMappingURL=compact-catalog-families.d.ts.map
|
|
@@ -18,7 +18,9 @@ const DIALOGS = familyId("dialogs");
|
|
|
18
18
|
* the members it enumerated and never an explicit empty, so a reader can tell "no members" from "not enumerated"
|
|
19
19
|
* (RULING-60 Q1, RULING-61 Q1). Members stream one at a time: a value goes through `walk` into bounded leaves, a
|
|
20
20
|
* collection through `rows`, and each component's leaves are released once the catalog has placed it. The
|
|
21
|
-
* completeness gate runs last: a complete producer that emitted nothing refuses the whole catalog (X03).
|
|
21
|
+
* completeness gate runs last: a complete producer that emitted nothing refuses the whole catalog (X03). Its return
|
|
22
|
+
* value is the registry it emitted as `families/families`, the one source the manifest copies `requiredKinds` from
|
|
23
|
+
* (RULING-128).
|
|
22
24
|
*/
|
|
23
25
|
export async function* checkpointComponents(cut, valid) {
|
|
24
26
|
const { store, values, root, settled } = cut;
|
|
@@ -26,7 +28,7 @@ export async function* checkpointComponents(cut, valid) {
|
|
|
26
28
|
if (!current)
|
|
27
29
|
throw new CompactReadError("unavailable");
|
|
28
30
|
const reader = { store, values, valid };
|
|
29
|
-
const producers = familyProducers(root
|
|
31
|
+
const producers = familyProducers(root);
|
|
30
32
|
const registry = familyRegistry(producers);
|
|
31
33
|
yield* textComponent(store, FAMILIES, FAMILIES, JSON.stringify(registry));
|
|
32
34
|
const family = (name) => {
|
|
@@ -66,6 +68,7 @@ export async function* checkpointComponents(cut, valid) {
|
|
|
66
68
|
yield component;
|
|
67
69
|
}
|
|
68
70
|
assertCoverage(registry, emitted);
|
|
71
|
+
return registry;
|
|
69
72
|
}
|
|
70
73
|
async function* dialogComponents(reader, ref) {
|
|
71
74
|
const dialogs = new CompactComponentRoots(reader.store, () => []);
|
|
@@ -26,7 +26,10 @@ export declare const FAMILY_PRODUCERS: FamilyProducers;
|
|
|
26
26
|
* correlation refused at the protocol depth limit never became the lane's standing one, so `identity` is then
|
|
27
27
|
* `partial` too: its member reports the count (RULING-67 (4)).
|
|
28
28
|
*/
|
|
29
|
-
export declare function familyProducers(
|
|
29
|
+
export declare function familyProducers(root: {
|
|
30
|
+
readonly transcript: TranscriptRoot;
|
|
31
|
+
readonly refusedCorrelations: number;
|
|
32
|
+
}): FamilyProducers;
|
|
30
33
|
/**
|
|
31
34
|
* Every engine source kind (the session file's entry union) and the family that owns its data. The compiler refuses
|
|
32
35
|
* a kind this map misses (TS2741), so a new engine entry type cannot ship uncataloged. A kind outside the union at
|
|
@@ -46,6 +49,11 @@ interface RegistryBase {
|
|
|
46
49
|
readonly format: "senpi-recovery-families";
|
|
47
50
|
readonly version: 1;
|
|
48
51
|
readonly families: readonly FamilyRow[];
|
|
52
|
+
/**
|
|
53
|
+
* The families a root built from these producers requires (RULING-128): every `complete` one, in code-unit order,
|
|
54
|
+
* each once. The manifest carries this exact list, and this component's digest is inside `checkpointDigest`.
|
|
55
|
+
*/
|
|
56
|
+
readonly requiredKinds: readonly CatalogFamily[];
|
|
49
57
|
}
|
|
50
58
|
/**
|
|
51
59
|
* Set only by `familyRegistry`, which `readFamilyRegistry` decodes through and `completeAssembly` narrows to, so no other
|
|
@@ -46,7 +46,8 @@ export const FAMILY_PRODUCERS = {
|
|
|
46
46
|
* correlation refused at the protocol depth limit never became the lane's standing one, so `identity` is then
|
|
47
47
|
* `partial` too: its member reports the count (RULING-67 (4)).
|
|
48
48
|
*/
|
|
49
|
-
export function familyProducers(
|
|
49
|
+
export function familyProducers(root) {
|
|
50
|
+
const { transcript, refusedCorrelations } = root;
|
|
50
51
|
const exact = transcript.unavailable === null;
|
|
51
52
|
const entries = exact
|
|
52
53
|
? {}
|
|
@@ -83,7 +84,11 @@ const COMPLETE = Symbol("complete family registry");
|
|
|
83
84
|
export function familyRegistry(producers) {
|
|
84
85
|
const families = CATALOG_FAMILIES.map((family) => ({ family, producer: producers[family] }));
|
|
85
86
|
const incomplete = families.filter(({ producer }) => producer !== "complete").map(({ family }) => family);
|
|
86
|
-
const
|
|
87
|
+
const requiredKinds = families
|
|
88
|
+
.filter(({ producer }) => producer === "complete")
|
|
89
|
+
.map(({ family }) => family)
|
|
90
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
91
|
+
const base = { format: "senpi-recovery-families", version: 1, families, requiredKinds };
|
|
87
92
|
return incomplete.length === 0
|
|
88
93
|
? { ...base, assembly: "complete", [COMPLETE]: true }
|
|
89
94
|
: { ...base, assembly: "incomplete", incomplete };
|
|
@@ -133,6 +138,8 @@ export function readFamilyRegistry(text) {
|
|
|
133
138
|
const registry = familyRegistry({ ...FAMILY_PRODUCERS, ...producers });
|
|
134
139
|
if (field(value, "assembly") !== registry.assembly)
|
|
135
140
|
throw new RangeError("family registry assembly mismatch");
|
|
141
|
+
if (JSON.stringify(field(value, "requiredKinds")) !== JSON.stringify(registry.requiredKinds))
|
|
142
|
+
throw new RangeError("family registry requiredKinds mismatch");
|
|
136
143
|
return registry;
|
|
137
144
|
}
|
|
138
145
|
//# sourceMappingURL=compact-catalog-registry.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CatalogFamily, type FamilyRegistry } from "./compact-catalog-registry.ts";
|
|
2
|
+
export type RequiredKindsRefusal = "manifest_missing_required_kinds" | "manifest_unknown_required_kind" | "manifest_required_kinds_mismatch";
|
|
3
|
+
export type RequiredKindsRead = {
|
|
4
|
+
readonly ok: true;
|
|
5
|
+
readonly requiredKinds: readonly CatalogFamily[];
|
|
6
|
+
} | {
|
|
7
|
+
readonly ok: false;
|
|
8
|
+
readonly code: RequiredKindsRefusal;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The families a client opens for one decoded manifest (RULING-128): its `requiredKinds`, read verbatim and never
|
|
12
|
+
* replaced by a built-in family list. `registry` is the cut's `families/families` component as `readFamilyRegistry`
|
|
13
|
+
* decodes it from bytes verified against the root entry that `checkpointDigest` covers. The digest covers that
|
|
14
|
+
* component, not the manifest field, so the list opens only when it equals the component's complete families.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readRequiredKinds(manifest: unknown, registry: FamilyRegistry): RequiredKindsRead;
|
|
17
|
+
//# sourceMappingURL=compact-recovery-manifest-kinds.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CATALOG_FAMILIES } from "./compact-catalog-registry.js";
|
|
2
|
+
const KNOWN = new Set(CATALOG_FAMILIES);
|
|
3
|
+
const isKnown = (kind) => typeof kind === "string" && KNOWN.has(kind);
|
|
4
|
+
/**
|
|
5
|
+
* The families a client opens for one decoded manifest (RULING-128): its `requiredKinds`, read verbatim and never
|
|
6
|
+
* replaced by a built-in family list. `registry` is the cut's `families/families` component as `readFamilyRegistry`
|
|
7
|
+
* decodes it from bytes verified against the root entry that `checkpointDigest` covers. The digest covers that
|
|
8
|
+
* component, not the manifest field, so the list opens only when it equals the component's complete families.
|
|
9
|
+
*/
|
|
10
|
+
export function readRequiredKinds(manifest, registry) {
|
|
11
|
+
const listed = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "requiredKinds") : undefined;
|
|
12
|
+
if (!Array.isArray(listed))
|
|
13
|
+
return { ok: false, code: "manifest_missing_required_kinds" };
|
|
14
|
+
if (!listed.every(isKnown))
|
|
15
|
+
return { ok: false, code: "manifest_unknown_required_kind" };
|
|
16
|
+
const complete = registry.requiredKinds;
|
|
17
|
+
if (listed.length !== complete.length || listed.some((kind, index) => kind !== complete[index]))
|
|
18
|
+
return { ok: false, code: "manifest_required_kinds_mismatch" };
|
|
19
|
+
return { ok: true, requiredKinds: complete };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=compact-recovery-manifest-kinds.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CatalogFamily } from "./compact-catalog-registry.ts";
|
|
1
2
|
import type { BoundedId, ContentDigest, ContentRef } from "./compact-recovery-ids.ts";
|
|
2
3
|
import type { RecoveryRouteKind } from "./compact-recovery-types.ts";
|
|
3
4
|
/** A manifest string: inline when it is a bounded protocol id, otherwise a ref to its exact stored value. */
|
|
@@ -31,6 +32,12 @@ export interface RecoveryManifest {
|
|
|
31
32
|
readonly checkpointDigest: ContentDigest;
|
|
32
33
|
readonly catalogRoot: ContentRef;
|
|
33
34
|
readonly catalogRootLength: number;
|
|
35
|
+
/**
|
|
36
|
+
* The catalog families this cut's root requires (RULING-128): its complete families only, sorted, each once. It is
|
|
37
|
+
* the `requiredKinds` of the cut's `families/families` registry, so `checkpointDigest` covers it; a client opens
|
|
38
|
+
* exactly these and never falls back to a built-in family list.
|
|
39
|
+
*/
|
|
40
|
+
readonly requiredKinds: readonly CatalogFamily[];
|
|
34
41
|
}
|
|
35
42
|
export declare const TEXT_FIELDS: readonly ["socketEpoch", "admissionId", "session", "sessionEpoch", "token", "leaf", "activeMessage", "turn"];
|
|
36
43
|
export type TextField = (typeof TEXT_FIELDS)[number];
|
|
@@ -128,12 +128,19 @@ export class RecoveryManifests {
|
|
|
128
128
|
valid();
|
|
129
129
|
};
|
|
130
130
|
const cut = { store, values: new CompactValues(store), root, settled: lane.settledOf(root) };
|
|
131
|
+
const emitted = {};
|
|
131
132
|
const components = async function* () {
|
|
132
133
|
yield* oversized.map(({ component }) => component);
|
|
133
|
-
yield* checkpointComponents(cut, check);
|
|
134
|
+
emitted.registry = yield* checkpointComponents(cut, check);
|
|
134
135
|
};
|
|
135
136
|
const built = await this.catalogs.build(store, ref, components(), check);
|
|
136
|
-
|
|
137
|
+
// The list is the cataloged registry's own (RULING-128): the bytes `checkpointDigest` covers, never a recompute.
|
|
138
|
+
const requiredKinds = emitted.registry?.requiredKinds;
|
|
139
|
+
if (!requiredKinds) {
|
|
140
|
+
this.catalogs.release(store, built);
|
|
141
|
+
throw new CompactReadError("ownership");
|
|
142
|
+
}
|
|
143
|
+
return await this.assemble(store, token, ref, built, oversized, texts, requiredKinds);
|
|
137
144
|
}
|
|
138
145
|
finally {
|
|
139
146
|
for (const { component } of oversized)
|
|
@@ -144,7 +151,7 @@ export class RecoveryManifests {
|
|
|
144
151
|
});
|
|
145
152
|
}
|
|
146
153
|
/** Owns `built` from here: a failure anywhere below releases the tree, so no owner outlives a refused build. */
|
|
147
|
-
async assemble(store, token, ref, built, oversized, texts) {
|
|
154
|
+
async assemble(store, token, ref, built, oversized, texts, requiredKinds) {
|
|
148
155
|
try {
|
|
149
156
|
let leftmost = ref;
|
|
150
157
|
for (let level = 1; level < built.depth; level++)
|
|
@@ -183,6 +190,7 @@ export class RecoveryManifests {
|
|
|
183
190
|
checkpointDigest: built.digest,
|
|
184
191
|
catalogRoot: ref,
|
|
185
192
|
catalogRootLength: built.length,
|
|
193
|
+
requiredKinds,
|
|
186
194
|
};
|
|
187
195
|
return { manifest, root: built, store };
|
|
188
196
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { compactUpdatesEnabled } from "../../core/engine-socket-flag.js";
|
|
2
2
|
import { CONNECTION_ROLE_FIXED, roleConnection } from "./connection-roles.js";
|
|
3
|
+
import { remoteOriginDeclaration } from "./remote-origin.js";
|
|
3
4
|
import { error } from "./session-router-errors.js";
|
|
4
5
|
/** Validate the full declaration before committing role, media, recovery or pending state. */
|
|
5
6
|
export function declareSocketClient(host, command) {
|
|
6
7
|
const peer = host.writer.currentConnection();
|
|
7
8
|
const selection = peer === undefined ? undefined : host.writer.compactSelection(peer);
|
|
8
9
|
const role = (caps) => host.connectionRoles.declare(roleConnection(peer), caps);
|
|
10
|
+
const origin = remoteOriginDeclaration(command.remoteOrigin, (declared) => host.connectionRoles.acceptsOrigin(roleConnection(peer), declared));
|
|
11
|
+
if ("refusal" in origin)
|
|
12
|
+
return error(command.id, command.type, origin.refusal);
|
|
9
13
|
const reason = selection
|
|
10
14
|
? selection.declare(command.capabilities, host.registry.supportsCompact?.() === true, role)
|
|
11
15
|
: command.capabilities !== undefined && !role(command.capabilities)
|
|
@@ -23,6 +27,8 @@ export function declareSocketClient(host, command) {
|
|
|
23
27
|
}
|
|
24
28
|
else if (command.capabilities !== undefined)
|
|
25
29
|
host.writer.setSoleSecretCapabilities(command.capabilities);
|
|
30
|
+
if (origin.origin !== undefined)
|
|
31
|
+
host.connectionRoles.declareOrigin(roleConnection(peer), origin.origin);
|
|
26
32
|
return {
|
|
27
33
|
id: command.id,
|
|
28
34
|
type: "response",
|
|
@@ -45,6 +45,7 @@ import { DURABLE_CLIENT_MESSAGE_ID_CAPABILITY } from "./client-admission-record.
|
|
|
45
45
|
import { ClientAdmissions } from "./client-admissions.js";
|
|
46
46
|
import { handleClientInput } from "./client-input-handler.js";
|
|
47
47
|
import { ConnectionQuestionBridge, degradeQuestion, sessionQuestionBridges } from "./connection-question-bridge.js";
|
|
48
|
+
import { remoteOriginDeclaration, remoteOriginField } from "./remote-origin.js";
|
|
48
49
|
import { advertisedCompactCapabilities, sessionDeclaration } from "./compact-negotiation.js";
|
|
49
50
|
import { ConnectionRoles, roleConnection } from "./connection-roles.js";
|
|
50
51
|
import { AUTH_KEY_VERIFY_CAPABILITY, AUTO_TITLE_SESSIONS_CAPABILITY, buildCustomUnsupportedRequest, CONTINUE_FROM_LEAF_CAPABILITY, DEFAULT_CUSTOM_EXTENSION_LABEL, EVAL_CELLS_CAPABILITY, EXTENSION_EVENTS_CAPABILITY, ENTRIES_TAIL_CAPABILITY, INTERACTIVE_USER_CAPABILITY, MEDIA_PLACEHOLDERS_CAPABILITY, PROVIDER_ACCOUNT_TEST_CAPABILITY, QUESTION_CAPABILITY, QUEUED_MESSAGE_REVISION_CAPABILITY, RESUME_SESSION_CAPABILITY, RETRY_FALLBACK_COMMAND_CAPABILITY, SESSION_HELD_CAPABILITY, TOOL_BARRIER_CAPABILITY, TASK_PARENT_CAPABILITY, } from "./custom-capability.js";
|
|
@@ -339,7 +340,8 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
339
340
|
const pendingExtensionRequests = new SessionExtensionUiRequests(uiRequestChanged);
|
|
340
341
|
const grantRequests = new Map();
|
|
341
342
|
sessionDialogRequests.set(session, pendingExtensionRequests);
|
|
342
|
-
const
|
|
343
|
+
const raiserOrigin = () => connectionRoles.originOf(options.clientInfo?.connectionId());
|
|
344
|
+
const questions = new ConnectionQuestionBridge(output, uiRequestChanged, () => options.clientInfo?.connectionId(), raiserOrigin);
|
|
343
345
|
let secretHandshake = false;
|
|
344
346
|
const secretOwners = new Map();
|
|
345
347
|
const secretCapable = (connection) => connectionRoles.has(connection, INTERACTIVE_USER_CAPABILITY) &&
|
|
@@ -381,6 +383,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
381
383
|
if (opts?.signal?.aborted)
|
|
382
384
|
return Promise.resolve(defaultValue);
|
|
383
385
|
const id = crypto.randomUUID();
|
|
386
|
+
const raised = { ...request, ...remoteOriginField(raiserOrigin()) };
|
|
384
387
|
return new Promise((resolve, reject) => {
|
|
385
388
|
let timeoutId;
|
|
386
389
|
const cleanup = () => {
|
|
@@ -403,7 +406,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
403
406
|
}, opts.timeout);
|
|
404
407
|
}
|
|
405
408
|
pendingExtensionRequests.set(id, {
|
|
406
|
-
frame: { type: "extension_ui_request", id, ...
|
|
409
|
+
frame: { type: "extension_ui_request", id, ...raised },
|
|
407
410
|
resolve: (response) => {
|
|
408
411
|
cleanup();
|
|
409
412
|
resolve(parseResponse(response));
|
|
@@ -412,7 +415,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
412
415
|
});
|
|
413
416
|
if (request.grantSelect === true)
|
|
414
417
|
grantRequests.set(id, options.clientInfo?.connectionId());
|
|
415
|
-
output({ type: "extension_ui_request", id, ...
|
|
418
|
+
output({ type: "extension_ui_request", id, ...raised });
|
|
416
419
|
});
|
|
417
420
|
}
|
|
418
421
|
const selectGrantDialog = (title, choices, opts) => createDialogPromise(opts, undefined, {
|
|
@@ -549,9 +552,17 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
549
552
|
},
|
|
550
553
|
async editor(title, prefill) {
|
|
551
554
|
const id = crypto.randomUUID();
|
|
555
|
+
const frame = {
|
|
556
|
+
type: "extension_ui_request",
|
|
557
|
+
id,
|
|
558
|
+
method: "editor",
|
|
559
|
+
title,
|
|
560
|
+
prefill,
|
|
561
|
+
...remoteOriginField(raiserOrigin()),
|
|
562
|
+
};
|
|
552
563
|
return new Promise((resolve, reject) => {
|
|
553
564
|
pendingExtensionRequests.set(id, {
|
|
554
|
-
frame
|
|
565
|
+
frame,
|
|
555
566
|
resolve: (response) => {
|
|
556
567
|
if ("cancelled" in response && response.cancelled) {
|
|
557
568
|
resolve(undefined);
|
|
@@ -565,7 +576,7 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
565
576
|
},
|
|
566
577
|
reject,
|
|
567
578
|
});
|
|
568
|
-
output(
|
|
579
|
+
output(frame);
|
|
569
580
|
});
|
|
570
581
|
},
|
|
571
582
|
addAutocompleteProvider() {
|
|
@@ -1164,9 +1175,14 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
|
|
|
1164
1175
|
// State
|
|
1165
1176
|
// =================================================================
|
|
1166
1177
|
case "set_client_info": {
|
|
1178
|
+
const origin = remoteOriginDeclaration(command.remoteOrigin, (declared) => connectionRoles.acceptsOrigin(currentConnectionId(), declared));
|
|
1179
|
+
if ("refusal" in origin)
|
|
1180
|
+
return error(id, "set_client_info", origin.refusal);
|
|
1167
1181
|
const next = sessionDeclaration(options, command, clientCapabilities, (caps) => connectionRoles.declare(currentConnectionId(), caps), replaceClientCapabilities);
|
|
1168
1182
|
if (next.refusal)
|
|
1169
1183
|
return error(id, "set_client_info", next.refusal);
|
|
1184
|
+
if (origin.origin !== undefined)
|
|
1185
|
+
connectionRoles.declareOrigin(currentConnectionId(), origin.origin);
|
|
1170
1186
|
clientCapabilities = next.capabilities;
|
|
1171
1187
|
if (command.capabilities !== undefined) {
|
|
1172
1188
|
secretHandshake = true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExtensionUIContext, QuestionRequest, QuestionResponse } from "../../core/extensions/types.ts";
|
|
2
2
|
import type { UiRequestChange } from "./snapshot-types.ts";
|
|
3
|
+
import { type RpcRemoteOrigin } from "./remote-origin.ts";
|
|
3
4
|
import type { RpcExtensionUIProgress, RpcExtensionUIResponse, RpcQuestionUiRequest } from "./rpc-types.ts";
|
|
4
5
|
type Options = Parameters<NonNullable<ExtensionUIContext["question"]>>[1];
|
|
5
6
|
export declare const sessionQuestionBridges: WeakMap<object, ConnectionQuestionBridge>;
|
|
@@ -9,7 +10,8 @@ export declare class ConnectionQuestionBridge {
|
|
|
9
10
|
private readonly output;
|
|
10
11
|
private readonly changed;
|
|
11
12
|
private readonly raiser;
|
|
12
|
-
|
|
13
|
+
private readonly origin;
|
|
14
|
+
constructor(output: (record: object) => void, changed?: (change?: UiRequestChange) => void, raiser?: () => string | undefined, origin?: () => RpcRemoteOrigin | undefined);
|
|
13
15
|
pendingQuestions(): RpcQuestionUiRequest[];
|
|
14
16
|
ask(request: QuestionRequest, opts?: Options): Promise<QuestionResponse>;
|
|
15
17
|
respond(response: RpcExtensionUIResponse, beforeAnswer?: () => void): boolean | "question_incomplete" | "question_already_resolved";
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { settledQuestionStatus, unansweredQuestionIds } from "./extension-ui-response.js";
|
|
2
|
+
import { remoteOriginField } from "./remote-origin.js";
|
|
2
3
|
export const sessionQuestionBridges = new WeakMap();
|
|
3
4
|
export class ConnectionQuestionBridge {
|
|
4
|
-
constructor(output, changed, raiser = () => undefined) {
|
|
5
|
+
constructor(output, changed, raiser = () => undefined, origin = () => undefined) {
|
|
5
6
|
this.pending = new Map();
|
|
6
7
|
this.resolved = new Set();
|
|
7
8
|
this.output = output;
|
|
8
9
|
this.changed = changed;
|
|
9
10
|
this.raiser = raiser;
|
|
11
|
+
this.origin = origin;
|
|
10
12
|
}
|
|
11
13
|
pendingQuestions() {
|
|
12
14
|
return [...this.pending.values()].map(({ frame }) => ({
|
|
@@ -27,6 +29,7 @@ export class ConnectionQuestionBridge {
|
|
|
27
29
|
waitForAnswer: request.waitForAnswer,
|
|
28
30
|
questions: request.questions,
|
|
29
31
|
raisedBy: this.raiser() ?? "agent",
|
|
32
|
+
...remoteOriginField(this.origin()),
|
|
30
33
|
timeout,
|
|
31
34
|
askedAtMs,
|
|
32
35
|
deadlineAtMs: askedAtMs + timeout,
|