@sema-agent/client-core 0.94.0 → 0.95.0
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 +341 -0
- package/README.md +70 -47
- package/dist/adapt/arms.js +5 -6
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.js +2 -2
- package/dist/adapt/wireShapes.js +3 -8
- package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
- package/dist/adapter/activeRunSelfHeal.js +20 -12
- package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -3
- package/dist/adapter/runStream.js +2 -1
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +3 -2
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +2 -6
- package/dist/atMostOnce.d.ts +8 -0
- package/dist/atMostOnce.js +36 -0
- package/dist/attachmentSeatCapability.d.ts +0 -1
- package/dist/attachmentSeatCapability.js +0 -3
- package/dist/attachmentsWireCaps.js +11 -6
- package/dist/bashExitReading.d.ts +10 -0
- package/dist/bashExitReading.js +12 -0
- package/dist/callerCwdCapability.d.ts +0 -1
- package/dist/callerCwdCapability.js +2 -7
- package/dist/centerWiringCapability.d.ts +1 -3
- package/dist/centerWiringCapability.js +18 -21
- package/dist/classifierStatus.js +4 -4
- package/dist/cloudConfigWireCaps.js +43 -21
- package/dist/compensations.js +1 -1
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +4 -1
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +41 -13
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +7 -16
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +313 -11
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +7 -2
- package/dist/engineCapsCache.js +64 -26
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +14 -3
- package/dist/engineErrorCodes.js +31 -10
- package/dist/engineIdentity.js +2 -0
- package/dist/engineWireSdk.js +2 -2
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +0 -1
- package/dist/fileHistoryCaptureCapability.js +2 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/fleetLedger.d.ts +2 -0
- package/dist/fleet/fleetLedger.js +69 -52
- package/dist/fleet/fleetProjection.d.ts +0 -3
- package/dist/fleet/fleetProjection.js +9 -16
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/gateOutcome.js +30 -18
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +10 -0
- package/dist/generated/settingsSchemaFns.js +22 -0
- package/dist/headlessPermissionModeWire.d.ts +1 -1
- package/dist/headlessPermissionModeWire.js +1 -1
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +5 -0
- package/dist/hitl/approvalEndingCause.js +61 -0
- package/dist/hitl/approvalHolds.d.ts +12 -2
- package/dist/hitl/approvalHolds.js +53 -2
- package/dist/hitl/approvalsFeed.js +23 -11
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +26 -1
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +43 -0
- package/dist/hitl/decisionRefusal.d.ts +4 -0
- package/dist/hitl/decisionRefusal.js +26 -1
- package/dist/hitl/frameRouter.js +26 -43
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +12 -1
- package/dist/hitl/hitlBridge.js +68 -53
- package/dist/hitl/hitlHostSurface.js +3 -11
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +3 -7
- package/dist/hitl/parkResolver.js +50 -26
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +56 -30
- package/dist/hitl/replayedApproval.d.ts +8 -0
- package/dist/hitl/replayedApproval.js +125 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/toolApprovalWire.d.ts +24 -4
- package/dist/hitl/toolApprovalWire.js +115 -38
- package/dist/hooksWireCaps.js +38 -6
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +25 -0
- package/dist/index.d.ts +30 -11
- package/dist/index.js +20 -8
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -0
- package/dist/limitsWire.js +49 -3
- package/dist/liveModelCatalog.d.ts +95 -0
- package/dist/liveModelCatalog.js +297 -32
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -1
- package/dist/mcpProbeCapability.js +2 -6
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -1
- package/dist/memoryComplianceCapability.js +2 -6
- package/dist/memoryOriginCapability.d.ts +0 -1
- package/dist/memoryOriginCapability.js +2 -6
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +4 -0
- package/dist/model/liveCatalogShape.d.ts +14 -0
- package/dist/model/liveCatalogShape.js +71 -0
- package/dist/model/modelSupplyRules.d.ts +1 -0
- package/dist/model/modelSupplyRules.js +30 -9
- package/dist/model/modelsPolicy.d.ts +21 -0
- package/dist/model/modelsPolicy.js +90 -0
- package/dist/modelIdentityResolvability.d.ts +1 -1
- package/dist/modelIdentityResolvability.js +5 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -1
- package/dist/outputStyleSeatCapability.js +2 -7
- package/dist/ownKey.d.ts +6 -0
- package/dist/ownKey.js +48 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -1
- package/dist/permissionModesCapability.js +5 -10
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +2 -6
- package/dist/permissionsAllowGrantCapability.d.ts +0 -1
- package/dist/permissionsAllowGrantCapability.js +3 -9
- package/dist/permissionsDeclaration.d.ts +6 -0
- package/dist/permissionsDeclaration.js +45 -0
- package/dist/printToolResultFrame.js +2 -10
- package/dist/promptDelivery.js +0 -8
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +126 -15
- package/dist/rewindArchiveCapability.d.ts +2 -1
- package/dist/rewindArchiveCapability.js +15 -7
- package/dist/rewindEngineAction.d.ts +21 -0
- package/dist/rewindEngineAction.js +36 -0
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +1 -0
- package/dist/runTerminal.d.ts +0 -11
- package/dist/runTerminal.js +4 -27
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -1
- package/dist/sealedKeyCapability.js +3 -9
- package/dist/seatContract.d.ts +54 -25
- package/dist/seatContract.js +394 -171
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +11 -0
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +6 -1
- package/dist/sessionMemoryStatus.js +3 -2
- package/dist/sessionPolicyCapability.d.ts +0 -1
- package/dist/sessionPolicyCapability.js +2 -6
- package/dist/sessionReadRedactionCapability.d.ts +0 -1
- package/dist/sessionReadRedactionCapability.js +2 -7
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
- package/dist/sessionSyncFileHistoryCapability.js +2 -6
- package/dist/skillToolListsCapability.d.ts +0 -1
- package/dist/skillToolListsCapability.js +2 -6
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +9 -14
- package/dist/steerPriorityCapability.d.ts +0 -1
- package/dist/steerPriorityCapability.js +3 -9
- package/dist/storePostureCapability.d.ts +1 -1
- package/dist/storePostureCapability.js +16 -16
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/engineCompactWire.js +13 -38
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +3 -3
- package/dist/supportFloor.js +2 -5
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolResult.d.ts +5 -0
- package/dist/toolResult.js +88 -36
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +311 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -1
- package/dist/userInvokedSkillsCapability.js +2 -6
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +42 -2
- package/dist/wireRefusalCopy.js +2 -18
- package/dist/workflowClient.js +7 -11
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +2 -6
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +5 -10
- package/docs/INTEGRATION-CLIENTS.md +1033 -26
- package/package.json +5 -5
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { ownDataField } from './ownKey.js';
|
|
3
4
|
import { MEMORY_ENGINE_REQUIRED_CODE } from './memoryComplianceCapability.js';
|
|
4
5
|
export function projectMemoryOriginCapability(caps) {
|
|
5
6
|
try {
|
|
6
7
|
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
7
8
|
return undefined;
|
|
8
9
|
const c = caps;
|
|
9
|
-
|
|
10
|
-
return { kind: 'not_reported' };
|
|
11
|
-
const v = c.memoryOrigin;
|
|
10
|
+
const v = ownDataField(c, 'memoryOrigin');
|
|
12
11
|
if (v === undefined)
|
|
13
12
|
return { kind: 'not_reported' };
|
|
14
13
|
if (typeof v !== 'boolean')
|
|
@@ -49,9 +48,6 @@ export function memoryOriginDoctorDetail(reading) {
|
|
|
49
48
|
return 'external-origin face on — the origin listing and clearance endpoints are mounted and the operator roster is non-empty on this engine; this says the door opens, not that any one call succeeds, and it says nothing about the listing being complete (the engine has no scope-enumeration read face, so an answer covers only the scopes the caller named and an empty one must never be read as a clean store)';
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
|
-
export function forgetMemoryOriginReading(baseUrl) {
|
|
53
|
-
reader.forget(baseUrl);
|
|
54
|
-
}
|
|
55
51
|
export function __resetMemoryOriginReadingsForTests() {
|
|
56
52
|
reader.__resetForTests();
|
|
57
53
|
}
|
|
@@ -21,7 +21,7 @@ export interface MemoryFacade {
|
|
|
21
21
|
}
|
|
22
22
|
export declare const MEMORY_VERB_REFUSAL_CAUSES: readonly ["face_absent", "client_too_old", "unreadable_request", "store_absent", "operator_only", "operators_unconfigured", "unauthorized", "service_token_required", "id_invalid", "request_id_required", "body_shape", "query_invalid", "selector_invalid", "evidence_unavailable", "selector_mismatch", "census_incomplete", "clear_unattributed", "clear_invalid", "clear_not_marked", "clear_challenged", "clear_conflict", "clear_pending"];
|
|
23
23
|
export type MemoryVerbRefusalCause = (typeof MEMORY_VERB_REFUSAL_CAUSES)[number];
|
|
24
|
-
export declare const MEMORY_VERB_UNKNOWN_WHYS: readonly ["no_verdict", "server_fault", "control_plane_corrupt", "clear_unknown", "clear_failed", "result_unreadable", "unsupported_version", "identity_mismatch", "unclassified"];
|
|
24
|
+
export declare const MEMORY_VERB_UNKNOWN_WHYS: readonly ["no_verdict", "server_fault", "control_plane_corrupt", "clear_unknown", "clear_failed", "result_unreadable", "unsupported_version", "identity_mismatch", "store_form_refused", "unclassified"];
|
|
25
25
|
export type MemoryVerbUnknownWhy = (typeof MEMORY_VERB_UNKNOWN_WHYS)[number];
|
|
26
26
|
export type MemoryVerbRefused = {
|
|
27
27
|
status: 'refused';
|
package/dist/memoryVerbsWire.js
CHANGED
|
@@ -35,6 +35,7 @@ export const MEMORY_VERB_UNKNOWN_WHYS = Object.freeze([
|
|
|
35
35
|
'result_unreadable',
|
|
36
36
|
'unsupported_version',
|
|
37
37
|
'identity_mismatch',
|
|
38
|
+
'store_form_refused',
|
|
38
39
|
'unclassified',
|
|
39
40
|
]);
|
|
40
41
|
function refusedBy(cause, message) {
|
|
@@ -90,6 +91,9 @@ export function classifyMemoryFailure(e) {
|
|
|
90
91
|
return unknownBy('clear_unknown', message);
|
|
91
92
|
case 'memory.origin_clear_failed':
|
|
92
93
|
return unknownBy('clear_failed', message);
|
|
94
|
+
case 'memory.target_outside_store':
|
|
95
|
+
case 'memory.scope_home_not_directory':
|
|
96
|
+
return unknownBy('store_form_refused', message);
|
|
93
97
|
case 'internal.memory_control_plane_corrupt':
|
|
94
98
|
return unknownBy('control_plane_corrupt', message);
|
|
95
99
|
default:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type FrozenJsonValue = string | number | boolean | null | readonly FrozenJsonValue[] | {
|
|
2
|
+
readonly [k: string]: FrozenJsonValue;
|
|
3
|
+
};
|
|
4
|
+
export declare function frozenJsonCopyOf(v: unknown): FrozenJsonValue | undefined;
|
|
5
|
+
export declare function liveModelRowCopy(row: unknown): FrozenJsonRow | undefined;
|
|
6
|
+
export type FrozenJsonRow = {
|
|
7
|
+
readonly [k: string]: FrozenJsonValue;
|
|
8
|
+
} & {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function liveDefaultModelCopy(v: unknown): {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly name?: string;
|
|
14
|
+
} | undefined;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const MAX_DEPTH = 16;
|
|
2
|
+
class Unreadable extends Error {
|
|
3
|
+
}
|
|
4
|
+
function frozenJsonCopy(v, depth) {
|
|
5
|
+
if (depth > MAX_DEPTH)
|
|
6
|
+
throw new Unreadable();
|
|
7
|
+
if (v === null || typeof v === 'string' || typeof v === 'boolean')
|
|
8
|
+
return v;
|
|
9
|
+
if (typeof v === 'number') {
|
|
10
|
+
if (!Number.isFinite(v))
|
|
11
|
+
throw new Unreadable();
|
|
12
|
+
return v;
|
|
13
|
+
}
|
|
14
|
+
if (typeof v !== 'object')
|
|
15
|
+
throw new Unreadable();
|
|
16
|
+
if (Array.isArray(v)) {
|
|
17
|
+
const n = Object.getOwnPropertyDescriptor(v, 'length')?.value;
|
|
18
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
19
|
+
throw new Unreadable();
|
|
20
|
+
const out = [];
|
|
21
|
+
for (let i = 0; i < n; i += 1) {
|
|
22
|
+
const d = Object.getOwnPropertyDescriptor(v, String(i));
|
|
23
|
+
if (d === undefined || !('value' in d))
|
|
24
|
+
throw new Unreadable();
|
|
25
|
+
out.push(frozenJsonCopy(d.value, depth + 1));
|
|
26
|
+
}
|
|
27
|
+
return Object.freeze(out);
|
|
28
|
+
}
|
|
29
|
+
const out = {};
|
|
30
|
+
for (const k of Object.keys(v)) {
|
|
31
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
32
|
+
if (d === undefined || !('value' in d))
|
|
33
|
+
throw new Unreadable();
|
|
34
|
+
if (d.value === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
Object.defineProperty(out, k, { value: frozenJsonCopy(d.value, depth + 1), enumerable: true, writable: true, configurable: true });
|
|
37
|
+
}
|
|
38
|
+
return Object.freeze(out);
|
|
39
|
+
}
|
|
40
|
+
export function frozenJsonCopyOf(v) {
|
|
41
|
+
try {
|
|
42
|
+
return frozenJsonCopy(v, 0);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function liveModelRowCopy(row) {
|
|
49
|
+
if (row === null || typeof row !== 'object' || Array.isArray(row))
|
|
50
|
+
return undefined;
|
|
51
|
+
const copy = frozenJsonCopyOf(row);
|
|
52
|
+
if (!isFrozenJsonObject(copy))
|
|
53
|
+
return undefined;
|
|
54
|
+
const name = copy.name;
|
|
55
|
+
return typeof name === 'string' && name.length > 0 ? copy : undefined;
|
|
56
|
+
}
|
|
57
|
+
const isFrozenJsonObject = (v) => v !== undefined && v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
58
|
+
export function liveDefaultModelCopy(v) {
|
|
59
|
+
if (v === null || typeof v !== 'object' || Array.isArray(v))
|
|
60
|
+
return undefined;
|
|
61
|
+
const c = frozenJsonCopyOf(v);
|
|
62
|
+
if (!isFrozenJsonObject(c))
|
|
63
|
+
return undefined;
|
|
64
|
+
const id = c.id;
|
|
65
|
+
const name = c.name;
|
|
66
|
+
if (typeof id !== 'string' || id.length === 0)
|
|
67
|
+
return undefined;
|
|
68
|
+
if (Object.hasOwn(c, 'name') && (typeof name !== 'string' || name.length === 0))
|
|
69
|
+
return undefined;
|
|
70
|
+
return c;
|
|
71
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SETTINGS_NARROW_AT_MENTION } from '../generated/settingsSchemaFns.js';
|
|
2
|
+
import { modelsPolicyOf } from './modelsPolicy.js';
|
|
1
3
|
import { inferFamily } from './providerPresets.js';
|
|
2
4
|
function isPlainObject(v) {
|
|
3
5
|
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
@@ -13,15 +15,16 @@ export function resolveEntryVision(entry) {
|
|
|
13
15
|
export function computeDeleteWarnings(input) {
|
|
14
16
|
const { id, doc, tierGroups, survivingIds } = input;
|
|
15
17
|
const out = [];
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
if (effectiveBefore.length > 0 && effectiveAfter.length === 0) {
|
|
18
|
+
const am = modelsPolicyOf(doc).atMention;
|
|
19
|
+
if (am?.kind === 'read' && am.value.mode === 'only') {
|
|
20
|
+
const before = SETTINGS_NARROW_AT_MENTION(am.value, new Set([id, ...survivingIds]));
|
|
21
|
+
const after = SETTINGS_NARROW_AT_MENTION(am.value, new Set(survivingIds.filter((n) => n !== id)));
|
|
22
|
+
if (before.mode === 'only' && after.mode === 'none') {
|
|
22
23
|
out.push({
|
|
23
24
|
kind: 'allowlist-empties',
|
|
24
|
-
consequence:
|
|
25
|
+
consequence: am.from === 'atModelAllowlist'
|
|
26
|
+
? 'it is the last usable model on your @-mention allowlist — deleting it empties the list, which means EVERY enabled model becomes @-mentionable'
|
|
27
|
+
: 'it is the last usable model on your @-mention allowlist — deleting it leaves no model that can be @-mentioned',
|
|
25
28
|
});
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -47,15 +50,33 @@ export function computeDeleteWarnings(input) {
|
|
|
47
50
|
export function computeDeleteBlockers(input) {
|
|
48
51
|
const { id, doc, rosters } = input;
|
|
49
52
|
const out = [];
|
|
50
|
-
|
|
53
|
+
const policy = modelsPolicyOf(doc);
|
|
54
|
+
if (policy.unreadable) {
|
|
55
|
+
out.push({
|
|
56
|
+
kind: 'unreadable',
|
|
57
|
+
where: 'models.json (the document could not be read)',
|
|
58
|
+
fix: 'fix or re-save models.json so it can be read, then delete this model',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (policy.defaultUnreadable) {
|
|
62
|
+
out.push({
|
|
63
|
+
kind: 'unreadable',
|
|
64
|
+
where: 'models.json `default` (the default model could not be read)',
|
|
65
|
+
fix: 'fix or re-save models.json so its default model can be read, then delete this model',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const dm = policy.defaultModel;
|
|
69
|
+
if (dm !== undefined && dm.name === id) {
|
|
51
70
|
out.push({
|
|
52
71
|
kind: 'default',
|
|
53
|
-
where: 'models.json `default`',
|
|
72
|
+
where: dm.from === 'default' ? 'models.json `default`' : 'models.json roles.default',
|
|
54
73
|
fix: 'point another model at the default first (Model Hub: select it and press u), then delete this one',
|
|
55
74
|
});
|
|
56
75
|
}
|
|
57
76
|
if (doc && isPlainObject(doc.roles)) {
|
|
58
77
|
for (const [role, target] of Object.entries(doc.roles)) {
|
|
78
|
+
if (role === 'default' && dm?.from === 'roles.default')
|
|
79
|
+
continue;
|
|
59
80
|
if (!isPlainObject(target) || typeof target.model !== 'string')
|
|
60
81
|
continue;
|
|
61
82
|
if (target.model !== id)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type SettingsAtMention } from '../generated/settingsSchemaFns.js';
|
|
2
|
+
export interface CanonicalDefaultModel {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly from: 'default' | 'roles.default';
|
|
5
|
+
}
|
|
6
|
+
export type CanonicalAtMention = {
|
|
7
|
+
readonly kind: 'read';
|
|
8
|
+
readonly value: SettingsAtMention;
|
|
9
|
+
readonly from: 'atMention' | 'atModelAllowlist';
|
|
10
|
+
readonly unreadableEntries: number;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'unreadable';
|
|
13
|
+
readonly from: 'atMention' | 'atModelAllowlist';
|
|
14
|
+
};
|
|
15
|
+
export interface CanonicalModelsPolicy {
|
|
16
|
+
readonly defaultModel?: CanonicalDefaultModel;
|
|
17
|
+
readonly defaultUnreadable?: true;
|
|
18
|
+
readonly atMention?: CanonicalAtMention;
|
|
19
|
+
readonly unreadable?: true;
|
|
20
|
+
}
|
|
21
|
+
export declare function modelsPolicyOf(doc: unknown): CanonicalModelsPolicy;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { SETTINGS_AT_MENTION_MODES } from '../generated/settingsSchemaFns.js';
|
|
2
|
+
function ownData(o, key) {
|
|
3
|
+
try {
|
|
4
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
5
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
12
|
+
function atMentionOf(v) {
|
|
13
|
+
try {
|
|
14
|
+
if (!isRecord(v))
|
|
15
|
+
return undefined;
|
|
16
|
+
const mode = ownData(v, 'mode');
|
|
17
|
+
if (typeof mode !== 'string' || !SETTINGS_AT_MENTION_MODES.includes(mode))
|
|
18
|
+
return undefined;
|
|
19
|
+
if (mode !== 'only')
|
|
20
|
+
return { mode: mode };
|
|
21
|
+
const list = ownData(v, 'models');
|
|
22
|
+
if (!Array.isArray(list) || list.length === 0)
|
|
23
|
+
return undefined;
|
|
24
|
+
const out = [];
|
|
25
|
+
for (let i = 0; i < list.length; i += 1) {
|
|
26
|
+
const d = Object.getOwnPropertyDescriptor(list, i);
|
|
27
|
+
if (d === undefined || !('value' in d) || typeof d.value !== 'string' || d.value.length === 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
out.push(d.value);
|
|
30
|
+
}
|
|
31
|
+
return { mode: 'only', models: out };
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function atModelAllowlistOf(v) {
|
|
38
|
+
if (!Array.isArray(v))
|
|
39
|
+
return { kind: 'unreadable', from: 'atModelAllowlist' };
|
|
40
|
+
const names = [];
|
|
41
|
+
let bad = 0;
|
|
42
|
+
for (let i = 0; i < v.length; i += 1) {
|
|
43
|
+
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
44
|
+
const x = d !== undefined && 'value' in d ? d.value : undefined;
|
|
45
|
+
if (typeof x === 'string' && x.length > 0)
|
|
46
|
+
names.push(x);
|
|
47
|
+
else
|
|
48
|
+
bad += 1;
|
|
49
|
+
}
|
|
50
|
+
const value = names.length > 0 ? { mode: 'only', models: names } : { mode: 'all' };
|
|
51
|
+
return { kind: 'read', value, from: 'atModelAllowlist', unreadableEntries: bad };
|
|
52
|
+
}
|
|
53
|
+
export function modelsPolicyOf(doc) {
|
|
54
|
+
try {
|
|
55
|
+
if (!isRecord(doc))
|
|
56
|
+
return {};
|
|
57
|
+
let defaultModel;
|
|
58
|
+
let defaultUnreadable = false;
|
|
59
|
+
if (Object.hasOwn(doc, 'default')) {
|
|
60
|
+
const d = ownData(doc, 'default');
|
|
61
|
+
if (typeof d === 'string' && d.length > 0)
|
|
62
|
+
defaultModel = { name: d, from: 'default' };
|
|
63
|
+
else
|
|
64
|
+
defaultUnreadable = true;
|
|
65
|
+
}
|
|
66
|
+
if (defaultModel === undefined && !defaultUnreadable) {
|
|
67
|
+
const roles = ownData(doc, 'roles');
|
|
68
|
+
const rd = isRecord(roles) ? ownData(roles, 'default') : undefined;
|
|
69
|
+
const model = isRecord(rd) ? ownData(rd, 'model') : undefined;
|
|
70
|
+
if (typeof model === 'string' && model.length > 0)
|
|
71
|
+
defaultModel = { name: model, from: 'roles.default' };
|
|
72
|
+
}
|
|
73
|
+
let atMention;
|
|
74
|
+
if (Object.hasOwn(doc, 'atMention')) {
|
|
75
|
+
const am = atMentionOf(ownData(doc, 'atMention'));
|
|
76
|
+
atMention = am === undefined ? { kind: 'unreadable', from: 'atMention' } : { kind: 'read', value: am, from: 'atMention', unreadableEntries: 0 };
|
|
77
|
+
}
|
|
78
|
+
else if (Object.hasOwn(doc, 'atModelAllowlist')) {
|
|
79
|
+
atMention = atModelAllowlistOf(ownData(doc, 'atModelAllowlist'));
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
...(defaultModel !== undefined ? { defaultModel } : {}),
|
|
83
|
+
...(defaultUnreadable ? { defaultUnreadable: true } : {}),
|
|
84
|
+
...(atMention !== undefined ? { atMention } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return { unreadable: true };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -28,7 +28,7 @@ export type ModelIdentityResolvability = 'resolvable' | 'not_resolvable' | 'unkn
|
|
|
28
28
|
export type ModelSetupDecision = 'offer_setup' | 'explain_unconfigured' | 'explain_route_gap' | 'proceed';
|
|
29
29
|
export declare function modelIdentityResolvability(reading: ModelIdentityReading): ModelIdentityResolvability;
|
|
30
30
|
export declare function modelIdentityDetail(reading: ModelIdentityReading): string;
|
|
31
|
-
export declare function modelSetupDecision(
|
|
31
|
+
export declare function modelSetupDecision(reading: ModelIdentityReading, hostCanConfigureModel: boolean): ModelSetupDecision;
|
|
32
32
|
export declare function modelSetupNotice(decision: ModelSetupDecision): string | null;
|
|
33
33
|
export declare function observedEngineAnswer(baseUrl?: string | undefined): EngineAnswerObservation;
|
|
34
34
|
export {};
|
|
@@ -178,18 +178,11 @@ export function modelIdentityDetail(reading) {
|
|
|
178
178
|
return "this reading of the engine's model configuration could not be interpreted, so whether the engine has a model name is unknown";
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
export function modelSetupDecision(
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
else {
|
|
187
|
-
const a = analyse(identity);
|
|
188
|
-
if (a.verdict === 'not_resolvable' && a.why === 'route_gap')
|
|
189
|
-
return 'explain_route_gap';
|
|
190
|
-
verdict = a.verdict;
|
|
191
|
-
}
|
|
192
|
-
if (verdict !== 'not_resolvable')
|
|
181
|
+
export function modelSetupDecision(reading, hostCanConfigureModel) {
|
|
182
|
+
const a = analyse(reading);
|
|
183
|
+
if (a.verdict === 'not_resolvable' && a.why === 'route_gap')
|
|
184
|
+
return 'explain_route_gap';
|
|
185
|
+
if (a.verdict !== 'not_resolvable')
|
|
193
186
|
return 'proceed';
|
|
194
187
|
if (hostCanConfigureModel === true)
|
|
195
188
|
return 'offer_setup';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type ModelSwitchProbeLane = 'live' | 'mock' | 'engine_absent' | 'unwired';
|
|
2
|
+
export interface ModelSwitchProbeVerdict {
|
|
3
|
+
readonly valid: boolean;
|
|
4
|
+
readonly error?: string;
|
|
5
|
+
readonly unchecked?: true;
|
|
6
|
+
}
|
|
7
|
+
export interface ModelSwitchProbeInput {
|
|
8
|
+
readonly model: string;
|
|
9
|
+
readonly lane: ModelSwitchProbeLane;
|
|
10
|
+
readonly engineAbsentReason?: string;
|
|
11
|
+
readonly probe?: {
|
|
12
|
+
readonly kind: 'verdict';
|
|
13
|
+
readonly verdict: ModelSwitchProbeVerdict;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'threw';
|
|
16
|
+
readonly error: unknown;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export type ModelSwitchProbeOutcome = {
|
|
20
|
+
readonly ok: true;
|
|
21
|
+
readonly probed: boolean;
|
|
22
|
+
} | {
|
|
23
|
+
readonly ok: false;
|
|
24
|
+
readonly kind: 'rejected';
|
|
25
|
+
readonly model: string;
|
|
26
|
+
readonly reason?: string;
|
|
27
|
+
} | {
|
|
28
|
+
readonly ok: false;
|
|
29
|
+
readonly kind: 'unavailable';
|
|
30
|
+
readonly cause: 'unwired' | 'probe_missing' | 'probe_threw' | 'unchecked';
|
|
31
|
+
readonly model: string;
|
|
32
|
+
readonly reason?: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function modelSwitchProbeOutcomeOf(input: ModelSwitchProbeInput): ModelSwitchProbeOutcome;
|
|
35
|
+
export interface ModelSwitchProbePorts {
|
|
36
|
+
readonly lane: () => {
|
|
37
|
+
readonly lane: ModelSwitchProbeLane;
|
|
38
|
+
readonly engineAbsentReason?: string;
|
|
39
|
+
} | Promise<{
|
|
40
|
+
readonly lane: ModelSwitchProbeLane;
|
|
41
|
+
readonly engineAbsentReason?: string;
|
|
42
|
+
}>;
|
|
43
|
+
readonly validate: (model: string) => Promise<ModelSwitchProbeVerdict>;
|
|
44
|
+
}
|
|
45
|
+
export declare function runModelSwitchProbe(model: string, ports: ModelSwitchProbePorts): Promise<ModelSwitchProbeOutcome>;
|
|
46
|
+
export interface ModelSwitchFallbackRecord {
|
|
47
|
+
readonly previous: string;
|
|
48
|
+
readonly current: string;
|
|
49
|
+
readonly seq: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ModelSwitchNote {
|
|
52
|
+
readonly sessionId: string;
|
|
53
|
+
readonly to: string | null | undefined;
|
|
54
|
+
readonly lastServed: string | null | undefined;
|
|
55
|
+
}
|
|
56
|
+
export interface ModelSwitchAdvisoryInput {
|
|
57
|
+
readonly frame: unknown;
|
|
58
|
+
readonly sessionId: string;
|
|
59
|
+
readonly streamModel: string | null | undefined;
|
|
60
|
+
readonly lastServed: string | null | undefined;
|
|
61
|
+
}
|
|
62
|
+
export interface ModelSwitchFallbackLedger {
|
|
63
|
+
noteSwitch(input: ModelSwitchNote): ModelSwitchFallbackRecord | undefined;
|
|
64
|
+
peek(sessionId: string): ModelSwitchFallbackRecord | undefined;
|
|
65
|
+
advisoryFor(input: ModelSwitchAdvisoryInput): ModelSwitchFallbackRecord | undefined;
|
|
66
|
+
release(sessionId: string, seq: number): boolean;
|
|
67
|
+
clear(sessionId: string): void;
|
|
68
|
+
}
|
|
69
|
+
export declare function createModelSwitchFallbackLedger(): ModelSwitchFallbackLedger;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { resultErrorCodeOf, resultSelectedModelOf } from './resultFrameKeys.js';
|
|
2
|
+
import { readFrameStringKey, readOwnDataValue } from './ownKey.js';
|
|
3
|
+
const trimmed = (v) => (typeof v === 'string' ? v.trim() : '');
|
|
4
|
+
const reasonOf = (v) => {
|
|
5
|
+
const t = trimmed(v);
|
|
6
|
+
return t.length > 0 ? t : undefined;
|
|
7
|
+
};
|
|
8
|
+
function thrownReason(e) {
|
|
9
|
+
try {
|
|
10
|
+
if (e instanceof Error)
|
|
11
|
+
return reasonOf(e.message);
|
|
12
|
+
return reasonOf(e);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function modelSwitchProbeOutcomeOf(input) {
|
|
19
|
+
let model = '';
|
|
20
|
+
let lane;
|
|
21
|
+
let absent;
|
|
22
|
+
let probe;
|
|
23
|
+
try {
|
|
24
|
+
model = trimmed(input?.model);
|
|
25
|
+
lane = input?.lane;
|
|
26
|
+
absent = reasonOf(input?.engineAbsentReason);
|
|
27
|
+
probe = input?.probe;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { ok: false, kind: 'unavailable', cause: 'probe_missing', model };
|
|
31
|
+
}
|
|
32
|
+
if (model.length === 0)
|
|
33
|
+
return { ok: true, probed: false };
|
|
34
|
+
if (lane === 'unwired')
|
|
35
|
+
return { ok: false, kind: 'unavailable', cause: 'unwired', model };
|
|
36
|
+
if (lane === 'mock' || (lane === 'engine_absent' && absent === undefined))
|
|
37
|
+
return { ok: true, probed: false };
|
|
38
|
+
if (lane !== 'live' && lane !== 'engine_absent')
|
|
39
|
+
return { ok: false, kind: 'unavailable', cause: 'unwired', model };
|
|
40
|
+
let kind;
|
|
41
|
+
let verdict;
|
|
42
|
+
let error;
|
|
43
|
+
try {
|
|
44
|
+
kind = probe?.kind;
|
|
45
|
+
verdict = kind === 'verdict' ? probe.verdict : undefined;
|
|
46
|
+
error = kind === 'threw' ? probe.error : undefined;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
kind = undefined;
|
|
50
|
+
}
|
|
51
|
+
if (kind === 'threw') {
|
|
52
|
+
const reason = thrownReason(error);
|
|
53
|
+
return { ok: false, kind: 'unavailable', cause: 'probe_threw', model, ...(reason !== undefined ? { reason } : {}) };
|
|
54
|
+
}
|
|
55
|
+
if (kind !== 'verdict' || verdict === null || typeof verdict !== 'object')
|
|
56
|
+
return { ok: false, kind: 'unavailable', cause: 'probe_missing', model };
|
|
57
|
+
let valid;
|
|
58
|
+
let unchecked;
|
|
59
|
+
let why;
|
|
60
|
+
try {
|
|
61
|
+
valid = verdict.valid;
|
|
62
|
+
unchecked = verdict.unchecked;
|
|
63
|
+
why = reasonOf(verdict.error);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return { ok: false, kind: 'unavailable', cause: 'probe_missing', model };
|
|
67
|
+
}
|
|
68
|
+
if (valid === true)
|
|
69
|
+
return { ok: true, probed: lane === 'live' };
|
|
70
|
+
if (unchecked === true) {
|
|
71
|
+
const reason = why ?? absent;
|
|
72
|
+
return { ok: false, kind: 'unavailable', cause: 'unchecked', model, ...(reason !== undefined ? { reason } : {}) };
|
|
73
|
+
}
|
|
74
|
+
return { ok: false, kind: 'rejected', model, ...(why !== undefined ? { reason: why } : {}) };
|
|
75
|
+
}
|
|
76
|
+
export async function runModelSwitchProbe(model, ports) {
|
|
77
|
+
let laneReading;
|
|
78
|
+
try {
|
|
79
|
+
const got = await ports.lane();
|
|
80
|
+
const lane = got?.lane;
|
|
81
|
+
const why = got?.engineAbsentReason;
|
|
82
|
+
laneReading = {
|
|
83
|
+
lane: lane === 'live' || lane === 'mock' || lane === 'engine_absent' || lane === 'unwired' ? lane : 'unwired',
|
|
84
|
+
...(typeof why === 'string' ? { engineAbsentReason: why } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
laneReading = { lane: 'unwired' };
|
|
89
|
+
}
|
|
90
|
+
const base = { model, ...laneReading };
|
|
91
|
+
const pre = modelSwitchProbeOutcomeOf(base);
|
|
92
|
+
if (pre.ok || (pre.kind === 'unavailable' && pre.cause !== 'probe_missing'))
|
|
93
|
+
return pre;
|
|
94
|
+
try {
|
|
95
|
+
const verdict = await ports.validate(trimmed(model));
|
|
96
|
+
return modelSwitchProbeOutcomeOf({ ...base, probe: { kind: 'verdict', verdict } });
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return modelSwitchProbeOutcomeOf({ ...base, probe: { kind: 'threw', error } });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const EMPTY_STREAM_ERROR_CODE = 'stream_torn';
|
|
103
|
+
const LEDGER_SESSION_CAP = 1024;
|
|
104
|
+
function isEmptyStreamFailureFrame(frame) {
|
|
105
|
+
try {
|
|
106
|
+
if (frame === null || typeof frame !== 'object' || Array.isArray(frame))
|
|
107
|
+
return false;
|
|
108
|
+
if (readFrameStringKey(frame, 'type') !== 'result')
|
|
109
|
+
return false;
|
|
110
|
+
if (readOwnDataValue(frame, 'is_error') !== true)
|
|
111
|
+
return false;
|
|
112
|
+
return resultErrorCodeOf(frame) === EMPTY_STREAM_ERROR_CODE;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function createModelSwitchFallbackLedger() {
|
|
119
|
+
const bySession = new Map();
|
|
120
|
+
let lastSeq = 0;
|
|
121
|
+
const drop = (sid) => {
|
|
122
|
+
if (sid.length > 0)
|
|
123
|
+
bySession.delete(sid);
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
noteSwitch(input) {
|
|
127
|
+
let sid = '';
|
|
128
|
+
let current = '';
|
|
129
|
+
let previous = '';
|
|
130
|
+
try {
|
|
131
|
+
sid = trimmed(input?.sessionId);
|
|
132
|
+
current = trimmed(input?.to);
|
|
133
|
+
previous = trimmed(input?.lastServed);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
if (sid.length === 0)
|
|
139
|
+
return undefined;
|
|
140
|
+
if (current.length === 0 || previous.length === 0 || previous === current) {
|
|
141
|
+
drop(sid);
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
lastSeq += 1;
|
|
145
|
+
const rec = Object.freeze({ previous, current, seq: lastSeq });
|
|
146
|
+
bySession.delete(sid);
|
|
147
|
+
bySession.set(sid, rec);
|
|
148
|
+
while (bySession.size > LEDGER_SESSION_CAP) {
|
|
149
|
+
const oldest = bySession.keys().next().value;
|
|
150
|
+
if (oldest === undefined)
|
|
151
|
+
break;
|
|
152
|
+
bySession.delete(oldest);
|
|
153
|
+
}
|
|
154
|
+
return rec;
|
|
155
|
+
},
|
|
156
|
+
peek(sessionId) {
|
|
157
|
+
const sid = trimmed(sessionId);
|
|
158
|
+
return sid.length > 0 ? bySession.get(sid) : undefined;
|
|
159
|
+
},
|
|
160
|
+
advisoryFor(input) {
|
|
161
|
+
let frame;
|
|
162
|
+
let sid = '';
|
|
163
|
+
let streamModel = '';
|
|
164
|
+
let served = '';
|
|
165
|
+
try {
|
|
166
|
+
frame = input?.frame;
|
|
167
|
+
sid = trimmed(input?.sessionId);
|
|
168
|
+
streamModel = trimmed(input?.streamModel);
|
|
169
|
+
served = trimmed(input?.lastServed);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
if (!isEmptyStreamFailureFrame(frame))
|
|
175
|
+
return undefined;
|
|
176
|
+
if (sid.length === 0)
|
|
177
|
+
return undefined;
|
|
178
|
+
const rec = bySession.get(sid);
|
|
179
|
+
if (rec === undefined)
|
|
180
|
+
return undefined;
|
|
181
|
+
const frameModel = trimmed(resultSelectedModelOf(frame));
|
|
182
|
+
const candidates = frameModel.length > 0 && frameModel !== streamModel ? [streamModel, frameModel] : [streamModel];
|
|
183
|
+
for (const c of candidates) {
|
|
184
|
+
if (c.length === 0 || rec.current !== c)
|
|
185
|
+
continue;
|
|
186
|
+
if (served === c)
|
|
187
|
+
return undefined;
|
|
188
|
+
return rec;
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
},
|
|
192
|
+
release(sessionId, seq) {
|
|
193
|
+
const sid = trimmed(sessionId);
|
|
194
|
+
if (sid.length === 0)
|
|
195
|
+
return false;
|
|
196
|
+
const rec = bySession.get(sid);
|
|
197
|
+
if (rec === undefined || typeof seq !== 'number' || rec.seq !== seq)
|
|
198
|
+
return false;
|
|
199
|
+
bySession.delete(sid);
|
|
200
|
+
return true;
|
|
201
|
+
},
|
|
202
|
+
clear(sessionId) {
|
|
203
|
+
drop(trimmed(sessionId));
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|