@code-yeongyu/senpi 2026.11.6-1 → 2026.11.6-2
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 +35 -0
- package/dist/bundle/chunks/{chunk-5MWHZH2O.js → chunk-2FDW2LQL.js} +1 -1
- package/dist/bundle/chunks/{chunk-GG2JO3CL.js → chunk-4E7GDG4H.js} +1 -1
- package/dist/bundle/chunks/{chunk-K5JLYACP.js → chunk-4GKU755E.js} +1 -1
- package/dist/bundle/chunks/{chunk-437VLZQZ.js → chunk-7III44PV.js} +1 -1
- package/dist/bundle/chunks/chunk-7PSBD5KS.js +9 -0
- package/dist/bundle/chunks/{chunk-KFWHLVVH.js → chunk-C7OKUC7L.js} +1 -1
- package/dist/bundle/chunks/{chunk-CX32K5KD.js → chunk-CF5OGBC4.js} +7 -7
- package/dist/bundle/chunks/{chunk-7TGZJH6Z.js → chunk-D5MRJWUK.js} +40 -39
- package/dist/bundle/chunks/{chunk-E6L5VZSM.js → chunk-DSWDJ7HT.js} +1 -1
- package/dist/bundle/chunks/{chunk-6NMTFURP.js → chunk-ECW7VBMB.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CSLJLM6.js → chunk-GKAYPJ4E.js} +2 -2
- package/dist/bundle/chunks/{chunk-KCGUUIUS.js → chunk-GNSMNSL7.js} +1 -1
- package/dist/bundle/chunks/{chunk-V3JSQ3PG.js → chunk-GSKCWXXG.js} +1 -1
- package/dist/bundle/chunks/{chunk-USKWGPA6.js → chunk-GTJJ73DE.js} +1 -1
- package/dist/bundle/chunks/{chunk-HHSYTDKO.js → chunk-HLM46XEB.js} +2 -2
- package/dist/bundle/chunks/{chunk-A4F4J2KH.js → chunk-I3PHVJAS.js} +2 -2
- package/dist/bundle/chunks/{chunk-LAMRXFHZ.js → chunk-LNPAT22L.js} +1 -1
- package/dist/bundle/chunks/chunk-NH7SYIGN.js +2 -0
- package/dist/bundle/chunks/{chunk-ZIIDIVTG.js → chunk-R2Z7CX77.js} +1 -1
- package/dist/bundle/chunks/{chunk-32I42CEY.js → chunk-RQ6CHXQ2.js} +1 -1
- package/dist/bundle/chunks/chunk-SJI6UB23.js +2 -0
- package/dist/bundle/chunks/{chunk-KUIEHAPR.js → chunk-T2SMQPRE.js} +1 -1
- package/dist/bundle/chunks/{chunk-IPG434JT.js → chunk-TIPKAMSS.js} +1 -1
- package/dist/bundle/chunks/{chunk-RI5ABX7A.js → chunk-TMXRR3N7.js} +2 -2
- package/dist/bundle/chunks/chunk-VD7AKTGP.js +3 -0
- package/dist/bundle/chunks/{chunk-22JICYKS.js → chunk-WAOGBBZR.js} +1 -1
- package/dist/bundle/chunks/{chunk-6MHCFJDB.js → chunk-WGRKM3N6.js} +2 -2
- package/dist/bundle/chunks/{chunk-WF5R2VSP.js → chunk-X5ZVYNOL.js} +1 -1
- package/dist/bundle/chunks/{chunk-H2FBGZNP.js → chunk-XCMII2VQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-5JUCTKYS.js → chunk-YK3ZZCHI.js} +1 -1
- package/dist/bundle/chunks/{cli-main-ZQBSX5H5.js → cli-main-T74YJGIF.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-7U7354GG.js → hand-entry-AYRUGE2A.js} +2 -2
- package/dist/bundle/chunks/{headless-host-7LKTG76U.js → headless-host-ES74ZB6M.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-NLSWH2CA.js → help-fast-path-TMTGLOBG.js} +1 -1
- package/dist/bundle/chunks/{host-command-3YRFN35E.js → host-command-YRXZE4TV.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-6XLVIECJ.js → host-lifecycle-6VCXMPDW.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +1 -1
- package/dist/bundle/chunks/{host-session-command-F7USXUZV.js → host-session-command-N7IN7ZDV.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-4RF3PUQ2.js → interactive-mode-B5SQDLH7.js} +1 -1
- package/dist/bundle/chunks/{list-tips-H6VGDFTS.js → list-tips-DU57HHKA.js} +1 -1
- package/dist/bundle/chunks/{main-G2SRZYQN.js → main-UQFVFCNY.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-RPN54GUC.js → multi-session-host-XSUJDHFZ.js} +5 -5
- package/dist/bundle/chunks/{openai-codex-responses-MJZKUS6I.js → openai-codex-responses-7V6LTDRU.js} +2 -2
- package/dist/bundle/chunks/{package-manager-cli-D2VFD463.js → package-manager-cli-GLUNPQJU.js} +1 -1
- package/dist/bundle/chunks/{role-37WVG42T.js → role-RRFFHZF5.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-QELPMM4N.js → rotation-stream-BN2YK2MC.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-P4D3DVYD.js → rpc-mode-JYN3E7P7.js} +1 -1
- package/dist/bundle/chunks/rpc-monitor-source-C6VQ3BC4.js +3 -0
- package/dist/bundle/chunks/{run-attached-tui-CGA6O5FR.js → run-attached-tui-W236SEOR.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-XWSNOAGG.js → schedule-command-B2EJTBOE.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-YIMLHGLG.js +3 -0
- package/dist/bundle/chunks/{session-picker-OA2AUVZG.js → session-picker-E6ZONUJB.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +294 -292
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +1 -1
- 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/cli/project-trust-headless.d.ts +13 -0
- package/dist/cli/project-trust-headless.js +35 -0
- package/dist/cli/project-trust.js +13 -50
- package/dist/cli/schedule-delivery.d.ts +4 -0
- package/dist/cli/schedule-delivery.js +6 -0
- package/dist/cli/schedule-runner.js +8 -0
- package/dist/cli/session-opening.d.ts +19 -0
- package/dist/cli/session-opening.js +47 -1
- package/dist/core/agent-session-runtime.d.ts +12 -0
- package/dist/core/agent-session-runtime.js +41 -0
- package/dist/core/agent-session.js +13 -22
- package/dist/core/egress/api-table.d.ts +121 -0
- package/dist/core/egress/api-table.js +41 -0
- package/dist/core/egress/classify.d.ts +19 -0
- package/dist/core/egress/classify.js +197 -0
- package/dist/core/egress/credential-fields.d.ts +18 -0
- package/dist/core/egress/credential-fields.js +83 -0
- package/dist/core/egress/custody-sidecar.d.ts +44 -0
- package/dist/core/egress/custody-sidecar.js +91 -0
- package/dist/core/egress/device-custody.d.ts +12 -0
- package/dist/core/egress/device-custody.js +82 -0
- package/dist/core/egress/endpoint.d.ts +33 -0
- package/dist/core/egress/endpoint.js +115 -0
- package/dist/core/execute-tool-on-host.d.ts +26 -0
- package/dist/core/execute-tool-on-host.js +96 -0
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +15 -0
- package/dist/core/extensions/builtin/goal/index.js +15 -3
- package/dist/core/extensions/builtin/goal/stop-pause.d.ts +2 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +5 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.d.ts +10 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.js +34 -6
- package/dist/core/extensions/builtin/herdr/index.js +6 -2
- package/dist/core/extensions/builtin/mcp/service.d.ts +9 -1
- package/dist/core/extensions/builtin/mcp/service.js +32 -1
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.d.ts +43 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.js +158 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.js +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.d.ts +5 -2
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.js +19 -4
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.js +15 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.d.ts +10 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.js +28 -2
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.d.ts +59 -0
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.js +15 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.js +14 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor-rpc.js +8 -1
- package/dist/core/extensions/loader.js +8 -0
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/foreign-session-holders.d.ts +1 -1
- package/dist/core/foreign-session-holders.js +3 -3
- package/dist/core/session-import/jsonl-import.d.ts +8 -12
- package/dist/core/session-import/jsonl-import.js +99 -40
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.js +7 -2
- package/dist/core/session-store/durable-binding.d.ts +2 -0
- package/dist/core/session-store/durable-binding.js +26 -4
- package/dist/core/settings-manager.d.ts +20 -0
- package/dist/core/settings-manager.js +51 -0
- package/dist/core/trust-manager.d.ts +1 -18
- package/dist/core/trust-manager.js +3 -124
- package/dist/core/trust-requiring-resources.d.ts +21 -0
- package/dist/core/trust-requiring-resources.js +189 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/main.js +42 -12
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/session-control-commands.js +2 -0
- package/dist/modes/rpc/connection-handler.js +17 -0
- package/dist/modes/rpc/connection-question-bridge.js +7 -4
- package/dist/modes/rpc/effect-commands.d.ts +24 -0
- package/dist/modes/rpc/host-boot-extensions.d.ts +4 -0
- package/dist/modes/rpc/host-boot-extensions.js +17 -0
- package/dist/modes/rpc/host-lifecycle-shutdown.js +11 -2
- package/dist/modes/rpc/loopless-runtime-settings.js +5 -1
- package/dist/modes/rpc/method-classes-schema-session.d.ts +33 -0
- package/dist/modes/rpc/method-classes-schema-session.js +4 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +33 -0
- package/dist/modes/rpc/method-classes.d.ts +4 -0
- package/dist/modes/rpc/method-classes.js +7 -0
- package/dist/modes/rpc/multi-session-host.d.ts +2 -0
- package/dist/modes/rpc/multi-session-host.js +7 -2
- package/dist/modes/rpc/project-workspace-commands.d.ts +60 -0
- package/dist/modes/rpc/project-workspace-commands.js +145 -0
- package/dist/modes/rpc/rpc-error-types.d.ts +11 -1
- package/dist/modes/rpc/rpc-error-types.js +10 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +15 -0
- package/dist/modes/rpc/session-attachment-gate.js +2 -0
- package/dist/modes/rpc/session-command-activity.js +2 -0
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +41 -2
- package/docs/extensions.md +17 -1
- package/docs/rpc.md +121 -4
- package/docs/terminal-tools.md +8 -0
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-FUQJK2TU.js +0 -2
- package/dist/bundle/chunks/chunk-POZMRM6V.js +0 -2
- package/dist/bundle/chunks/chunk-XBG63MJZ.js +0 -8
- package/dist/bundle/chunks/chunk-YP47G4YP.js +0 -3
- package/dist/bundle/chunks/rpc-monitor-source-KKN2UP4T.js +0 -3
- package/dist/bundle/chunks/session-control-endpoint-OST7WAKP.js +0 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { sessionHolderWarning } from "../core/foreign-session-holders.js";
|
|
2
|
+
import { checkSessionHolders, describeSessionHolders, SESSION_HOLDER_LOOKUP_FAILED, sessionHolderWarning, stopSessionHolders, takeOverRefusal, } from "../core/foreign-session-holders.js";
|
|
3
3
|
/** Warn after the runtime publishes its holder; an advisory lookup must not abort startup. */
|
|
4
4
|
export async function prepareSessionOpening(manager, mode) {
|
|
5
5
|
if (mode === "interactive") {
|
|
@@ -8,4 +8,50 @@ export async function prepareSessionOpening(manager, mode) {
|
|
|
8
8
|
console.error(chalk.yellow(`Warning: ${warning}`));
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Exit code of a startup refused because another live process holds the session. The schedule runner reads it to
|
|
13
|
+
* leave the occurrence pending instead of failing it (senpi#5756).
|
|
14
|
+
*/
|
|
15
|
+
export const SESSION_HELD_EXIT_CODE = 76;
|
|
16
|
+
const RETRY = "then open it again";
|
|
17
|
+
/**
|
|
18
|
+
* Startup admission for a session another live process holds (senpi#5756, the startup path of #5744): opening it
|
|
19
|
+
* would start a second run of the same session. Without a person to ask it is refused with the holder named; on a
|
|
20
|
+
* terminal the person chooses to cancel or to take over (the holder is asked to exit first, as /resume does).
|
|
21
|
+
*/
|
|
22
|
+
export async function admitStartupSession(sessionFile, io) {
|
|
23
|
+
if (sessionFile === undefined)
|
|
24
|
+
return "open";
|
|
25
|
+
const check = await (io.lookup ?? checkSessionHolders)(sessionFile);
|
|
26
|
+
if ("lookupFailed" in check) {
|
|
27
|
+
io.err(chalk.yellow(`Warning: ${SESSION_HOLDER_LOOKUP_FAILED}`));
|
|
28
|
+
return "open";
|
|
29
|
+
}
|
|
30
|
+
const { holders } = check;
|
|
31
|
+
if (holders.length === 0)
|
|
32
|
+
return "open";
|
|
33
|
+
const held = `This session is open in another process (${describeSessionHolders(holders)}); opening it here would start a second run of the same session.`;
|
|
34
|
+
const refusal = takeOverRefusal(holders, RETRY);
|
|
35
|
+
if (!io.canAsk || refusal !== undefined) {
|
|
36
|
+
io.err(chalk.red(`Not opened: ${held} ${refusal ?? `Quit it there, ${RETRY}.`}`));
|
|
37
|
+
return "refused";
|
|
38
|
+
}
|
|
39
|
+
if (!(await io.confirm(`${held}\nTake over (stop it there)?`))) {
|
|
40
|
+
io.err(`Not opened: the session is open in another process (${describeSessionHolders(holders)}).`);
|
|
41
|
+
return "cancelled";
|
|
42
|
+
}
|
|
43
|
+
let stopped;
|
|
44
|
+
try {
|
|
45
|
+
stopped = await stopSessionHolders(sessionFile, holders);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
io.err(chalk.red(`Not opened: could not stop the other process (${error instanceof Error ? error.message : String(error)}).`));
|
|
49
|
+
return "refused";
|
|
50
|
+
}
|
|
51
|
+
if (!stopped) {
|
|
52
|
+
io.err(chalk.red(`Not opened: the session is still open in another process; quit it there, ${RETRY}.`));
|
|
53
|
+
return "refused";
|
|
54
|
+
}
|
|
55
|
+
return "open";
|
|
56
|
+
}
|
|
11
57
|
//# sourceMappingURL=session-opening.js.map
|
|
@@ -143,6 +143,11 @@ export declare class AgentSessionRuntime {
|
|
|
143
143
|
private syncFullAccessTrust;
|
|
144
144
|
/** Settles when the rebuild that followed a Full-access trust change has finished. */
|
|
145
145
|
get projectTrustChange(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Runs `task` after every trust change already started here and before any started later (senpi#6176), so an
|
|
148
|
+
* explicit trust decision and a Full access sync never read each other's saved value mid-change.
|
|
149
|
+
*/
|
|
150
|
+
runInProjectTrustChangeOrder<T>(task: () => Promise<T>): Promise<T>;
|
|
146
151
|
private _projectTrustChange;
|
|
147
152
|
/** Failed trust rebuilds; kept across session replacement so the error stays visible. */
|
|
148
153
|
private _trustChangeDiagnostics;
|
|
@@ -208,12 +213,19 @@ export declare class AgentSessionRuntime {
|
|
|
208
213
|
importFromJsonl(inputPath: string, cwdOverride?: string): Promise<{
|
|
209
214
|
cancelled: boolean;
|
|
210
215
|
}>;
|
|
216
|
+
/**
|
|
217
|
+
* Abort the active run, waiting at most the #3711 quit budget. Arming the budget first makes this wait count
|
|
218
|
+
* against the same total the `session_shutdown` handlers share, so a turn held by an extension cannot delay quit
|
|
219
|
+
* past it.
|
|
220
|
+
*/
|
|
221
|
+
private endActiveRunWithinQuitBudget;
|
|
211
222
|
/**
|
|
212
223
|
* `processExit`: the caller exits the process right after, so quit-time handlers share the total quit budget
|
|
213
224
|
* (senpi#3711). An RPC host closing one session leaves it unset and keeps only the per-handler limits.
|
|
214
225
|
*/
|
|
215
226
|
dispose(options?: {
|
|
216
227
|
readonly processExit?: boolean;
|
|
228
|
+
readonly endActiveRun?: boolean;
|
|
217
229
|
}): Promise<void>;
|
|
218
230
|
}
|
|
219
231
|
/**
|
|
@@ -157,6 +157,15 @@ export class AgentSessionRuntime {
|
|
|
157
157
|
get projectTrustChange() {
|
|
158
158
|
return this._projectTrustChange;
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Runs `task` after every trust change already started here and before any started later (senpi#6176), so an
|
|
162
|
+
* explicit trust decision and a Full access sync never read each other's saved value mid-change.
|
|
163
|
+
*/
|
|
164
|
+
runInProjectTrustChangeOrder(task) {
|
|
165
|
+
const run = this._projectTrustChange.then(task);
|
|
166
|
+
this._projectTrustChange = run.then(() => undefined, () => undefined);
|
|
167
|
+
return run;
|
|
168
|
+
}
|
|
160
169
|
/**
|
|
161
170
|
* Gives this process's sessions their fallback policy (`set_retry_fallback`); later replacements
|
|
162
171
|
* (switch, new, fork) keep it. Callers set it before the first turn: a chain never changes under a
|
|
@@ -516,11 +525,43 @@ export class AgentSessionRuntime {
|
|
|
516
525
|
await this.finishSessionReplacement();
|
|
517
526
|
return { cancelled: false };
|
|
518
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Abort the active run, waiting at most the #3711 quit budget. Arming the budget first makes this wait count
|
|
530
|
+
* against the same total the `session_shutdown` handlers share, so a turn held by an extension cannot delay quit
|
|
531
|
+
* past it.
|
|
532
|
+
*/
|
|
533
|
+
async endActiveRunWithinQuitBudget(processExit) {
|
|
534
|
+
if (processExit)
|
|
535
|
+
this.session.extensionRunner.armProcessExitBudget();
|
|
536
|
+
const budgetMs = this.services.settingsManager.getSessionShutdownQuitBudgetMs();
|
|
537
|
+
if (budgetMs === 0) {
|
|
538
|
+
await this.session.abort();
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
let timer;
|
|
542
|
+
try {
|
|
543
|
+
await Promise.race([
|
|
544
|
+
this.session.abort(),
|
|
545
|
+
new Promise((resolve) => {
|
|
546
|
+
timer = setTimeout(resolve, budgetMs);
|
|
547
|
+
}),
|
|
548
|
+
]);
|
|
549
|
+
}
|
|
550
|
+
finally {
|
|
551
|
+
if (timer !== undefined)
|
|
552
|
+
clearTimeout(timer);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
519
555
|
/**
|
|
520
556
|
* `processExit`: the caller exits the process right after, so quit-time handlers share the total quit budget
|
|
521
557
|
* (senpi#3711). An RPC host closing one session leaves it unset and keeps only the per-handler limits.
|
|
522
558
|
*/
|
|
523
559
|
async dispose(options = {}) {
|
|
560
|
+
// A person quitting ends the active run first, as teardownCurrent() does (senpi#5753). Otherwise
|
|
561
|
+
// `session_shutdown` tears extension resources down under a running tool and the loop sends that failure
|
|
562
|
+
// to the model in one more request. Host closes keep their own bounded abort handling.
|
|
563
|
+
if (options.endActiveRun === true)
|
|
564
|
+
await this.endActiveRunWithinQuitBudget(options.processExit === true);
|
|
524
565
|
await emitSessionShutdownEvent(this.session.extensionRunner, { type: "session_shutdown", reason: "quit" }, options);
|
|
525
566
|
this.beforeSessionInvalidate?.();
|
|
526
567
|
this.session.dispose();
|
|
@@ -18,6 +18,7 @@ import { rm } from "node:fs/promises";
|
|
|
18
18
|
import { dirname } from "node:path";
|
|
19
19
|
import { isDeepStrictEqual } from "node:util";
|
|
20
20
|
import { bindPipelineWitness } from "./execution/pipeline-witness.js";
|
|
21
|
+
import { runExecuteToolOnHost } from "./execute-tool-on-host.js";
|
|
21
22
|
import { carryPreflightFacts } from "./execution/preflight-carry.js";
|
|
22
23
|
import { ProviderRetryWatchdogAbortError, prepareAgentToolCall, resolveToolNameAlias, runToolCall, } from "@earendil-works/pi-agent-core";
|
|
23
24
|
import { localDeviceFiles } from "@earendil-works/pi-agent-core/node";
|
|
@@ -3859,31 +3860,21 @@ export class AgentSession {
|
|
|
3859
3860
|
if (beforeResult?.block) {
|
|
3860
3861
|
throw new ExecuteToolError("blocked", toolName, beforeResult.reason || "Tool execution was blocked", activeTools);
|
|
3861
3862
|
}
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
type: "text",
|
|
3873
|
-
text: err instanceof Error ? err.message : String(err),
|
|
3874
|
-
},
|
|
3875
|
-
],
|
|
3876
|
-
details: { isError: true },
|
|
3877
|
-
};
|
|
3878
|
-
isError = true;
|
|
3879
|
-
}
|
|
3880
|
-
const hookResult = await this._emitAfterToolCallHooks(prepared.toolCall, prepared.args, result, isError);
|
|
3881
|
-
if (!hookResult) {
|
|
3863
|
+
const { result, hook } = await runExecuteToolOnHost({
|
|
3864
|
+
agent: this.agent,
|
|
3865
|
+
afterHooks: (call, result, isError) => this._emitAfterToolCallHooks(call.toolCall, call.args, result, isError),
|
|
3866
|
+
}, prepared, {
|
|
3867
|
+
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
3868
|
+
...(options?.onUpdate === undefined
|
|
3869
|
+
? {}
|
|
3870
|
+
: { onUpdate: options.onUpdate }),
|
|
3871
|
+
});
|
|
3872
|
+
if (!hook) {
|
|
3882
3873
|
return result;
|
|
3883
3874
|
}
|
|
3884
3875
|
return {
|
|
3885
|
-
content:
|
|
3886
|
-
details: (
|
|
3876
|
+
content: hook.content ?? result.content,
|
|
3877
|
+
details: (hook.details ?? result.details),
|
|
3887
3878
|
terminate: result.terminate,
|
|
3888
3879
|
};
|
|
3889
3880
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-api facts the custody route decision reads (custody design 2.3 and 5, row CK5).
|
|
3
|
+
*
|
|
4
|
+
* `capability` says where a call of this api can run; `fetchInjection` is "yes" only when every
|
|
5
|
+
* request of the api goes through the `fetch` the caller injects (otherwise the sealed route could
|
|
6
|
+
* not supply the key below the seam, so the call goes to a device); `sdkLogging` is the knob that
|
|
7
|
+
* turns the api's SDK logging off. An api missing from the table (an extension-registered one) is
|
|
8
|
+
* treated as an ambient-credential api with unknown fetch injection, which routes it to a device.
|
|
9
|
+
*/
|
|
10
|
+
import type { ProviderCapability } from "./classify.ts";
|
|
11
|
+
export type FetchInjection = "yes" | "no" | "unknown";
|
|
12
|
+
export type SdkLoggingKnob = {
|
|
13
|
+
readonly kind: "none";
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "client-option";
|
|
16
|
+
readonly option: "logLevel";
|
|
17
|
+
readonly off: "off";
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "unknown";
|
|
20
|
+
};
|
|
21
|
+
export interface ApiFacts {
|
|
22
|
+
readonly capability: ProviderCapability;
|
|
23
|
+
readonly fetchInjection: FetchInjection;
|
|
24
|
+
readonly sdkLogging: SdkLoggingKnob;
|
|
25
|
+
}
|
|
26
|
+
export declare const API_FACTS: {
|
|
27
|
+
readonly "openai-completions": {
|
|
28
|
+
readonly capability: "cloud";
|
|
29
|
+
readonly fetchInjection: "yes";
|
|
30
|
+
readonly sdkLogging: {
|
|
31
|
+
readonly kind: "client-option";
|
|
32
|
+
readonly option: "logLevel";
|
|
33
|
+
readonly off: "off";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly "openai-responses": {
|
|
37
|
+
readonly capability: "cloud";
|
|
38
|
+
readonly fetchInjection: "no";
|
|
39
|
+
readonly sdkLogging: {
|
|
40
|
+
readonly kind: "client-option";
|
|
41
|
+
readonly option: "logLevel";
|
|
42
|
+
readonly off: "off";
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
readonly "azure-openai-responses": {
|
|
46
|
+
readonly capability: "cloud";
|
|
47
|
+
readonly fetchInjection: "yes";
|
|
48
|
+
readonly sdkLogging: {
|
|
49
|
+
readonly kind: "client-option";
|
|
50
|
+
readonly option: "logLevel";
|
|
51
|
+
readonly off: "off";
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
readonly "openai-codex-responses": {
|
|
55
|
+
readonly capability: "cloud";
|
|
56
|
+
readonly fetchInjection: "no";
|
|
57
|
+
readonly sdkLogging: {
|
|
58
|
+
readonly kind: "none";
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
readonly "mistral-conversations": {
|
|
62
|
+
readonly capability: "cloud";
|
|
63
|
+
readonly fetchInjection: "yes";
|
|
64
|
+
readonly sdkLogging: {
|
|
65
|
+
readonly kind: "none";
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
readonly "anthropic-messages": {
|
|
69
|
+
readonly capability: "cloud";
|
|
70
|
+
readonly fetchInjection: "yes";
|
|
71
|
+
readonly sdkLogging: {
|
|
72
|
+
readonly kind: "client-option";
|
|
73
|
+
readonly option: "logLevel";
|
|
74
|
+
readonly off: "off";
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
readonly "pi-messages": {
|
|
78
|
+
readonly capability: "cloud";
|
|
79
|
+
readonly fetchInjection: "yes";
|
|
80
|
+
readonly sdkLogging: {
|
|
81
|
+
readonly kind: "none";
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
readonly "google-generative-ai": {
|
|
85
|
+
readonly capability: "cloud";
|
|
86
|
+
readonly fetchInjection: "no";
|
|
87
|
+
readonly sdkLogging: {
|
|
88
|
+
readonly kind: "none";
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
readonly "google-vertex": {
|
|
92
|
+
readonly capability: "ambient-credential";
|
|
93
|
+
readonly fetchInjection: "no";
|
|
94
|
+
readonly sdkLogging: {
|
|
95
|
+
readonly kind: "none";
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
readonly "bedrock-converse-stream": {
|
|
99
|
+
readonly capability: "ambient-credential";
|
|
100
|
+
readonly fetchInjection: "no";
|
|
101
|
+
readonly sdkLogging: {
|
|
102
|
+
readonly kind: "unknown";
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
readonly "devin-agent": {
|
|
106
|
+
readonly capability: "cloud";
|
|
107
|
+
readonly fetchInjection: "no";
|
|
108
|
+
readonly sdkLogging: {
|
|
109
|
+
readonly kind: "none";
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
readonly "cursor-agent": {
|
|
113
|
+
readonly capability: "callback-stream";
|
|
114
|
+
readonly fetchInjection: "no";
|
|
115
|
+
readonly sdkLogging: {
|
|
116
|
+
readonly kind: "none";
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export declare function apiFacts(api: string | undefined): ApiFacts;
|
|
121
|
+
//# sourceMappingURL=api-table.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-api facts the custody route decision reads (custody design 2.3 and 5, row CK5).
|
|
3
|
+
*
|
|
4
|
+
* `capability` says where a call of this api can run; `fetchInjection` is "yes" only when every
|
|
5
|
+
* request of the api goes through the `fetch` the caller injects (otherwise the sealed route could
|
|
6
|
+
* not supply the key below the seam, so the call goes to a device); `sdkLogging` is the knob that
|
|
7
|
+
* turns the api's SDK logging off. An api missing from the table (an extension-registered one) is
|
|
8
|
+
* treated as an ambient-credential api with unknown fetch injection, which routes it to a device.
|
|
9
|
+
*/
|
|
10
|
+
const NO_SDK_LOGGER = { kind: "none" };
|
|
11
|
+
const SDK_LOG_LEVEL_OFF = { kind: "client-option", option: "logLevel", off: "off" };
|
|
12
|
+
export const API_FACTS = {
|
|
13
|
+
"openai-completions": { capability: "cloud", fetchInjection: "yes", sdkLogging: SDK_LOG_LEVEL_OFF },
|
|
14
|
+
"openai-responses": { capability: "cloud", fetchInjection: "no", sdkLogging: SDK_LOG_LEVEL_OFF },
|
|
15
|
+
"azure-openai-responses": { capability: "cloud", fetchInjection: "yes", sdkLogging: SDK_LOG_LEVEL_OFF },
|
|
16
|
+
"openai-codex-responses": { capability: "cloud", fetchInjection: "no", sdkLogging: NO_SDK_LOGGER },
|
|
17
|
+
"mistral-conversations": { capability: "cloud", fetchInjection: "yes", sdkLogging: NO_SDK_LOGGER },
|
|
18
|
+
"anthropic-messages": { capability: "cloud", fetchInjection: "yes", sdkLogging: SDK_LOG_LEVEL_OFF },
|
|
19
|
+
"pi-messages": { capability: "cloud", fetchInjection: "yes", sdkLogging: NO_SDK_LOGGER },
|
|
20
|
+
"google-generative-ai": { capability: "cloud", fetchInjection: "no", sdkLogging: NO_SDK_LOGGER },
|
|
21
|
+
"google-vertex": { capability: "ambient-credential", fetchInjection: "no", sdkLogging: NO_SDK_LOGGER },
|
|
22
|
+
"bedrock-converse-stream": {
|
|
23
|
+
capability: "ambient-credential",
|
|
24
|
+
fetchInjection: "no",
|
|
25
|
+
sdkLogging: { kind: "unknown" },
|
|
26
|
+
},
|
|
27
|
+
"devin-agent": { capability: "cloud", fetchInjection: "no", sdkLogging: NO_SDK_LOGGER },
|
|
28
|
+
"cursor-agent": { capability: "callback-stream", fetchInjection: "no", sdkLogging: NO_SDK_LOGGER },
|
|
29
|
+
};
|
|
30
|
+
const UNKNOWN_API = {
|
|
31
|
+
capability: "ambient-credential",
|
|
32
|
+
fetchInjection: "unknown",
|
|
33
|
+
sdkLogging: { kind: "unknown" },
|
|
34
|
+
};
|
|
35
|
+
function isTabledApi(api) {
|
|
36
|
+
return Object.hasOwn(API_FACTS, api);
|
|
37
|
+
}
|
|
38
|
+
export function apiFacts(api) {
|
|
39
|
+
return api !== undefined && isTabledApi(api) ? API_FACTS[api] : UNKNOWN_API;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=api-table.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field classification for the provider surface (custody design 5, row CK5).
|
|
3
|
+
*
|
|
4
|
+
* Every field a user can author in models.json, auth.json and the credential pool has exactly one
|
|
5
|
+
* class: "public" travels as plain config inside the encrypted account config; "sealed" is a secret
|
|
6
|
+
* value sealed per field and opened only for the request that uses it; "device-only" never leaves
|
|
7
|
+
* the owner device; "endpoint" is a URL split by `splitEndpoint`. A field with no entry here has no
|
|
8
|
+
* class, and the classification tests fail on it, so a new field cannot reach the brain unreviewed.
|
|
9
|
+
*/
|
|
10
|
+
/** "forces-device": a value present moves the whole provider to device custody (no sealed field kind exists for it). */
|
|
11
|
+
export type FieldClass = "public" | "sealed" | "device-only" | "endpoint" | "forces-device";
|
|
12
|
+
export type Custody = "sealed" | "device";
|
|
13
|
+
export type ProviderCapability = "cloud" | "local-only" | "ambient-credential" | "callback-stream";
|
|
14
|
+
/** models.json, keyed by schema path: `.` nests, `[]` is an array item, `.{key}` a record key, `.*` a record value. */
|
|
15
|
+
export declare const MODELS_JSON_FIELD_CLASSES: Readonly<Record<string, FieldClass>>;
|
|
16
|
+
/** Fields the runtime types add on top of the models.json schema (`model-config.ts`). */
|
|
17
|
+
export declare const MODELS_JSON_TYPE_ONLY_FIELDS: Readonly<Record<string, FieldClass>>;
|
|
18
|
+
export declare function classifyModelsJsonField(path: string): FieldClass | undefined;
|
|
19
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field classification for the provider surface (custody design 5, row CK5).
|
|
3
|
+
*
|
|
4
|
+
* Every field a user can author in models.json, auth.json and the credential pool has exactly one
|
|
5
|
+
* class: "public" travels as plain config inside the encrypted account config; "sealed" is a secret
|
|
6
|
+
* value sealed per field and opened only for the request that uses it; "device-only" never leaves
|
|
7
|
+
* the owner device; "endpoint" is a URL split by `splitEndpoint`. A field with no entry here has no
|
|
8
|
+
* class, and the classification tests fail on it, so a new field cannot reach the brain unreviewed.
|
|
9
|
+
*/
|
|
10
|
+
const COST = [
|
|
11
|
+
"input",
|
|
12
|
+
"output",
|
|
13
|
+
"cacheRead",
|
|
14
|
+
"cacheWrite",
|
|
15
|
+
"tiers[].inputTokensAbove",
|
|
16
|
+
"tiers[].input",
|
|
17
|
+
"tiers[].output",
|
|
18
|
+
"tiers[].cacheRead",
|
|
19
|
+
"tiers[].cacheWrite",
|
|
20
|
+
];
|
|
21
|
+
const PERCENTILES = ["", ".p50", ".p75", ".p90", ".p99"];
|
|
22
|
+
const COMPAT = [
|
|
23
|
+
"supportsWebSearch",
|
|
24
|
+
"supportsStore",
|
|
25
|
+
"supportsDeveloperRole",
|
|
26
|
+
"supportsReasoningEffort",
|
|
27
|
+
"supportsUsageInStreaming",
|
|
28
|
+
"supportsFinishReason",
|
|
29
|
+
"maxTokensField",
|
|
30
|
+
"requiresToolResultName",
|
|
31
|
+
"requiresAssistantAfterToolResult",
|
|
32
|
+
"requiresThinkingAsText",
|
|
33
|
+
"requiresReasoningContentOnAssistantMessages",
|
|
34
|
+
"supportsDisabledThinking",
|
|
35
|
+
"thinkingFormat",
|
|
36
|
+
"chatTemplateKwargs.{key}",
|
|
37
|
+
"chatTemplateKwargs.*",
|
|
38
|
+
"chatTemplateKwargs.*.$var",
|
|
39
|
+
"chatTemplateKwargs.*.omitWhenOff",
|
|
40
|
+
"cacheControlFormat",
|
|
41
|
+
...[
|
|
42
|
+
"allow_fallbacks",
|
|
43
|
+
"require_parameters",
|
|
44
|
+
"data_collection",
|
|
45
|
+
"zdr",
|
|
46
|
+
"enforce_distillable_text",
|
|
47
|
+
"order[]",
|
|
48
|
+
"only[]",
|
|
49
|
+
"ignore[]",
|
|
50
|
+
"quantizations[]",
|
|
51
|
+
"sort",
|
|
52
|
+
"sort.by",
|
|
53
|
+
"sort.partition",
|
|
54
|
+
...["prompt", "completion", "image", "audio", "request"].map((part) => `max_price.${part}`),
|
|
55
|
+
...PERCENTILES.map((suffix) => `preferred_min_throughput${suffix}`),
|
|
56
|
+
...PERCENTILES.map((suffix) => `preferred_max_latency${suffix}`),
|
|
57
|
+
].map((field) => `openRouterRouting.${field}`),
|
|
58
|
+
"vercelGatewayRouting.only[]",
|
|
59
|
+
"vercelGatewayRouting.order[]",
|
|
60
|
+
"zaiToolStream",
|
|
61
|
+
"supportsStrictMode",
|
|
62
|
+
"toolCallFormat",
|
|
63
|
+
"sendSessionAffinityHeaders",
|
|
64
|
+
"deferredToolsMode",
|
|
65
|
+
"sessionAffinityFormat",
|
|
66
|
+
"supportsLongCacheRetention",
|
|
67
|
+
"supportsForcedToolChoice",
|
|
68
|
+
"webSearchToolType",
|
|
69
|
+
"supportsWebSocket",
|
|
70
|
+
"supportsRemoteCompactionV2",
|
|
71
|
+
"supportsWebSearchPreview",
|
|
72
|
+
"supportsToolSearch",
|
|
73
|
+
"supportsEagerToolInputStreaming",
|
|
74
|
+
"supportsCacheControlOnTools",
|
|
75
|
+
"supportsTemperature",
|
|
76
|
+
"supportsToolChoice",
|
|
77
|
+
"forceAdaptiveThinking",
|
|
78
|
+
"allowEmptySignature",
|
|
79
|
+
"supportsToolReferences",
|
|
80
|
+
"allowedFallbackModels[].provider",
|
|
81
|
+
"allowedFallbackModels[].model",
|
|
82
|
+
...COST.map((field) => `allowedFallbackModels[].cost.${field}`),
|
|
83
|
+
];
|
|
84
|
+
const THINKING_LEVEL_MAP = ["off", "minimal", "low", "medium", "high", "xhigh", "max"].map((level) => `thinkingLevelMap.${level}`);
|
|
85
|
+
const INPUT_LIMITS = [
|
|
86
|
+
"maxRequestBytes",
|
|
87
|
+
"images.resize.maxWidth",
|
|
88
|
+
"images.resize.maxHeight",
|
|
89
|
+
"images.resize.maxBytes",
|
|
90
|
+
"images.resize.jpegQuality",
|
|
91
|
+
"images.maxPerMessage",
|
|
92
|
+
"images.maxPerRequest",
|
|
93
|
+
].map((field) => `inputLimits.${field}`);
|
|
94
|
+
const MODEL_DEFINITION = {
|
|
95
|
+
...fields("public", [
|
|
96
|
+
"id",
|
|
97
|
+
"name",
|
|
98
|
+
"upstreamModelId",
|
|
99
|
+
"serviceTier",
|
|
100
|
+
"promptPreset",
|
|
101
|
+
"recoverTextToolCalls",
|
|
102
|
+
"api",
|
|
103
|
+
"reasoning",
|
|
104
|
+
...THINKING_LEVEL_MAP,
|
|
105
|
+
"defaultThinkingLevel",
|
|
106
|
+
"input[]",
|
|
107
|
+
...INPUT_LIMITS,
|
|
108
|
+
...COST.map((field) => `cost.${field}`),
|
|
109
|
+
"promptCache.short",
|
|
110
|
+
"promptCache.long",
|
|
111
|
+
"contextWindow",
|
|
112
|
+
"maxTokens",
|
|
113
|
+
"cacheRetention",
|
|
114
|
+
...COMPAT.map((field) => `compat.${field}`),
|
|
115
|
+
"headers.{key}",
|
|
116
|
+
"extraBody.{key}",
|
|
117
|
+
]),
|
|
118
|
+
baseUrl: "endpoint",
|
|
119
|
+
"headers.*": "sealed",
|
|
120
|
+
"extraBody.*": "forces-device",
|
|
121
|
+
};
|
|
122
|
+
const MODEL_OVERRIDE = {
|
|
123
|
+
...fields("public", [
|
|
124
|
+
"name",
|
|
125
|
+
"promptPreset",
|
|
126
|
+
"recoverTextToolCalls",
|
|
127
|
+
"reasoning",
|
|
128
|
+
...THINKING_LEVEL_MAP,
|
|
129
|
+
"thinkingLevelMapMode",
|
|
130
|
+
"input[]",
|
|
131
|
+
...INPUT_LIMITS,
|
|
132
|
+
...COMPAT.map((field) => `compat.${field}`),
|
|
133
|
+
...COST.map((field) => `cost.${field}`),
|
|
134
|
+
"promptCache.short",
|
|
135
|
+
"promptCache.long",
|
|
136
|
+
"contextWindow",
|
|
137
|
+
"maxTokens",
|
|
138
|
+
"cacheRetention",
|
|
139
|
+
"headers.{key}",
|
|
140
|
+
"extraBody.{key}",
|
|
141
|
+
]),
|
|
142
|
+
"headers.*": "sealed",
|
|
143
|
+
"extraBody.*": "forces-device",
|
|
144
|
+
};
|
|
145
|
+
const PROVIDER = {
|
|
146
|
+
...fields("public", [
|
|
147
|
+
"name",
|
|
148
|
+
"disabled",
|
|
149
|
+
"api",
|
|
150
|
+
"headers.{key}",
|
|
151
|
+
"extraBody.{key}",
|
|
152
|
+
"cacheRetention",
|
|
153
|
+
"authHeader",
|
|
154
|
+
"whitelist[]",
|
|
155
|
+
"blacklist[]",
|
|
156
|
+
"hideFreeModels",
|
|
157
|
+
...COMPAT.map((field) => `compat.${field}`),
|
|
158
|
+
"credentials.rotation",
|
|
159
|
+
"credentials.affinity",
|
|
160
|
+
"credentials.accountStrategy",
|
|
161
|
+
"credentials.cooldownBaseMs",
|
|
162
|
+
"credentials.cooldownCapMs",
|
|
163
|
+
"credentials.slots.{key}",
|
|
164
|
+
"modelOverrides.{key}",
|
|
165
|
+
]),
|
|
166
|
+
baseUrl: "endpoint",
|
|
167
|
+
apiKey: "sealed",
|
|
168
|
+
"headers.*": "sealed",
|
|
169
|
+
"extraBody.*": "forces-device",
|
|
170
|
+
"credentials.slots.*.value": "sealed",
|
|
171
|
+
"credentials.slots.*.env": "device-only",
|
|
172
|
+
...prefixed("models[].", MODEL_DEFINITION),
|
|
173
|
+
...prefixed("modelOverrides.*.", MODEL_OVERRIDE),
|
|
174
|
+
};
|
|
175
|
+
/** models.json, keyed by schema path: `.` nests, `[]` is an array item, `.{key}` a record key, `.*` a record value. */
|
|
176
|
+
export const MODELS_JSON_FIELD_CLASSES = {
|
|
177
|
+
"disabledProviders[]": "public",
|
|
178
|
+
"providers.{key}": "public",
|
|
179
|
+
...prefixed("providers.*.", PROVIDER),
|
|
180
|
+
};
|
|
181
|
+
/** Fields the runtime types add on top of the models.json schema (`model-config.ts`). */
|
|
182
|
+
export const MODELS_JSON_TYPE_ONLY_FIELDS = {
|
|
183
|
+
"providers.*.models[].samplingParams.{key}": "public",
|
|
184
|
+
"providers.*.models[].samplingParams.*": "forces-device",
|
|
185
|
+
"providers.*.modelOverrides.*.samplingParams.{key}": "public",
|
|
186
|
+
"providers.*.modelOverrides.*.samplingParams.*": "forces-device",
|
|
187
|
+
};
|
|
188
|
+
export function classifyModelsJsonField(path) {
|
|
189
|
+
return MODELS_JSON_FIELD_CLASSES[path] ?? MODELS_JSON_TYPE_ONLY_FIELDS[path];
|
|
190
|
+
}
|
|
191
|
+
function fields(fieldClass, paths) {
|
|
192
|
+
return Object.fromEntries(paths.map((path) => [path, fieldClass]));
|
|
193
|
+
}
|
|
194
|
+
function prefixed(prefix, table) {
|
|
195
|
+
return Object.fromEntries(Object.entries(table).map(([path, fieldClass]) => [`${prefix}${path}`, fieldClass]));
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=classify.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FieldClass } from "./classify.ts";
|
|
2
|
+
export declare const CREDENTIAL_SLOT_FIELDS: {
|
|
3
|
+
readonly name: "public";
|
|
4
|
+
readonly displayName: "device-only";
|
|
5
|
+
readonly source: "public";
|
|
6
|
+
readonly key: "sealed";
|
|
7
|
+
readonly access: "sealed";
|
|
8
|
+
readonly refresh: "device-only";
|
|
9
|
+
readonly expires: "public";
|
|
10
|
+
readonly route: "public";
|
|
11
|
+
readonly env: "forces-device";
|
|
12
|
+
};
|
|
13
|
+
/** A stored credential key outside the declared fields (OAuth flows may add any) keeps the credential on the device. */
|
|
14
|
+
export declare function classifyCredentialField(type: "api_key" | "oauth", key: string): FieldClass;
|
|
15
|
+
export type CredentialDeviceReason = "env" | "undeclared-field";
|
|
16
|
+
/** Why a stored auth.json credential must be used on the device; empty when sealed custody can compose its requests. */
|
|
17
|
+
export declare function credentialDeviceReasons(credential: Readonly<Record<string, unknown>>): readonly CredentialDeviceReason[];
|
|
18
|
+
//# sourceMappingURL=credential-fields.d.ts.map
|