@sema-agent/client-core 0.112.1 → 0.113.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 +130 -0
- package/README.md +36 -23
- package/dist/adapt/arms.js +7 -1
- package/dist/adapt/textStream.d.ts +2 -0
- package/dist/adapt/textStream.js +27 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +7 -5
- package/dist/adapter/activeRunSelfHeal.js +38 -66
- package/dist/adapter/downstream/eventToSdkMessage.js +4 -0
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +8 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +36 -1
- package/dist/adapter/runStream.d.ts +2 -12
- package/dist/adapter/runStream.js +46 -19
- package/dist/agentSession/engineAgentRegistryRead.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/attachmentOutcome.d.ts +35 -0
- package/dist/attachmentOutcome.js +192 -0
- package/dist/attachmentPathPlan.d.ts +67 -0
- package/dist/attachmentPathPlan.js +203 -0
- package/dist/attachmentRoute.d.ts +9 -1
- package/dist/attachmentRoute.js +23 -2
- package/dist/declared/supportFloorDeclared.d.ts +1 -1
- package/dist/declared/supportFloorDeclared.js +1 -0
- package/dist/deviceRebind.js +2 -3
- package/dist/displayUntrusted.js +126 -19
- package/dist/engineAddress.d.ts +1 -1
- package/dist/engineAddress.js +9 -6
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +4 -0
- package/dist/engineNoticeCodes.d.ts +34 -4
- package/dist/engineNoticeCodes.js +133 -6
- package/dist/engineUnavailable.d.ts +4 -2
- package/dist/engineUnavailable.js +99 -17
- package/dist/fleet/fleetLedger.d.ts +9 -3
- package/dist/fleet/fleetLedger.js +112 -16
- package/dist/fleet/fleetProjection.d.ts +5 -0
- package/dist/fleet/fleetProjection.js +9 -1
- package/dist/gateVocabulary.d.ts +7 -0
- package/dist/gateVocabulary.js +40 -14
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +198 -2
- package/dist/generated/engineNoticeTables.js +56 -8
- package/dist/generated/settingsSchemaFns.d.ts +7 -0
- package/dist/generated/settingsSchemaFns.js +11 -0
- package/dist/generated/settingsSchemaHash.d.ts +1 -0
- package/dist/generated/settingsSchemaHash.js +58 -0
- package/dist/generated/settingsSchemaOwnKeyRead.js +6 -1
- package/dist/generated/settingsSchemaTables.d.ts +3 -2
- package/dist/generated/settingsSchemaTables.js +14 -0
- package/dist/generated/settingsSchemaTightenVerdict.d.ts +1 -0
- package/dist/generated/settingsSchemaTightenVerdict.js +125 -0
- package/dist/headlessPermissionModeWire.d.ts +7 -2
- package/dist/headlessPermissionModeWire.js +77 -8
- package/dist/hitl/approvalDecisionDoor.d.ts +24 -0
- package/dist/hitl/approvalDecisionDoor.js +77 -0
- package/dist/hitl/approvalDelivery.d.ts +6 -0
- package/dist/hitl/approvalDelivery.js +57 -7
- package/dist/hitl/approvalResolution.d.ts +6 -3
- package/dist/hitl/approvalResolution.js +24 -2
- package/dist/hitl/approvalsFeed.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/decisionSend.d.ts +7 -4
- package/dist/hitl/decisionSend.js +90 -41
- package/dist/hitl/frameRouter.d.ts +3 -3
- package/dist/hitl/frameRouter.js +5 -0
- package/dist/hitl/hitlHostSurface.d.ts +3 -2
- package/dist/hitl/hitlHostSurface.js +5 -3
- package/dist/hitl/legacyApprovalShapes.d.ts +142 -0
- package/dist/hitl/legacyApprovalShapes.js +1 -0
- package/dist/hitl/livePendingAsk.d.ts +4 -4
- package/dist/hitl/livePendingAsk.js +5 -3
- package/dist/hitl/parkResolver.js +1 -1
- package/dist/hitl/persistedRulesWire.js +2 -2
- package/dist/hitl/planReviewCard.d.ts +2 -1
- package/dist/hitl/planReviewCard.js +64 -1
- package/dist/hitl/planReviewWire.d.ts +30 -0
- package/dist/hitl/planReviewWire.js +204 -65
- package/dist/hitl/sessionPolicyWire.js +16 -7
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +11 -0
- package/dist/hitl/toolApprovalWire.d.ts +34 -10
- package/dist/hitl/toolApprovalWire.js +182 -33
- package/dist/hookMatcherVerdict.d.ts +2 -1
- package/dist/hookMatcherVerdict.js +3 -2
- package/dist/hooksReaderGenerations.d.ts +8 -0
- package/dist/hooksReaderGenerations.js +49 -0
- package/dist/hooksWireCaps.js +43 -18
- package/dist/hostSettingsSource.d.ts +1 -1
- package/dist/hostSettingsSource.js +2 -2
- package/dist/hostTurnSettings.d.ts +2 -2
- package/dist/hostTurnSettings.js +87 -47
- package/dist/humanTurn.d.ts +2 -1
- package/dist/humanTurn.js +44 -13
- package/dist/humanTurnRead.d.ts +7 -0
- package/dist/humanTurnRead.js +23 -14
- package/dist/humanTurnSentences.js +3 -0
- package/dist/i18n/messages.en.d.ts +91 -5
- package/dist/i18n/messages.en.js +98 -12
- package/dist/i18n/messages.zh.js +108 -15
- package/dist/index.d.ts +29 -15
- package/dist/index.js +17 -9
- package/dist/liveModelCatalog.js +1 -0
- package/dist/liveQuestionStore.d.ts +2 -0
- package/dist/liveQuestionStore.js +7 -2
- package/dist/localConfig/kernel.d.ts +2 -1
- package/dist/localConfig/kernel.js +12 -18
- package/dist/localConfig/mcp/edit.js +25 -27
- package/dist/localConfig/mcp/servers.js +5 -8
- package/dist/localConfig/modelPool.d.ts +6 -1
- package/dist/localConfig/modelPool.js +104 -27
- package/dist/localConfig/modelPoolWords.d.ts +2 -0
- package/dist/localConfig/modelPoolWords.js +1 -0
- package/dist/localConfig/settingsWrite.js +1 -14
- package/dist/localConfig/skills.js +9 -16
- package/dist/localEngineSpawn.d.ts +29 -1
- package/dist/localEngineSpawn.js +62 -1
- package/dist/mcpLiveness.d.ts +1 -1
- package/dist/mcpProbeWire.js +2 -2
- package/dist/mcpReconnect.js +2 -2
- package/dist/model/catalogLoader.js +3 -17
- package/dist/model/onboardJudgement.d.ts +8 -0
- package/dist/model/onboardJudgement.js +8 -3
- package/dist/model/onboardSteps.d.ts +19 -0
- package/dist/model/onboardSteps.js +76 -0
- package/dist/notifications.js +6 -0
- package/dist/ownKey.d.ts +4 -0
- package/dist/ownKey.js +61 -0
- package/dist/pathShape.d.ts +14 -0
- package/dist/pathShape.js +44 -0
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +20 -3
- package/dist/pluginHooksWire.d.ts +20 -8
- package/dist/pluginHooksWire.js +204 -86
- package/dist/prepareRefusal.d.ts +2 -0
- package/dist/prepareRefusal.js +11 -1
- package/dist/request/taskRequest.js +3 -1
- package/dist/resultFrameKeys.d.ts +1 -0
- package/dist/resultFrameKeys.js +3 -0
- package/dist/resumeRefusalCopy.js +3 -1
- package/dist/retryStatus.d.ts +11 -1
- package/dist/retryStatus.js +15 -4
- package/dist/runTerminal.d.ts +1 -0
- package/dist/runTerminal.js +15 -1
- package/dist/sdkWireTransit.d.ts +1 -1
- package/dist/seatContract.d.ts +12 -3
- package/dist/seatContract.js +24 -13
- package/dist/sessionEngine.js +1 -1
- package/dist/sessionHooksRoster.js +8 -6
- package/dist/sessionIdSegment.d.ts +0 -1
- package/dist/sessionIdSegment.js +1 -3
- package/dist/sessionMemoryErase.js +2 -2
- package/dist/sessionMemoryStatus.js +2 -1
- package/dist/sessionOccupant.d.ts +29 -0
- package/dist/sessionOccupant.js +78 -0
- package/dist/settingsHooksSalvage.d.ts +4 -1
- package/dist/settingsHooksSalvage.js +22 -9
- package/dist/skillOverrideChain.d.ts +3 -0
- package/dist/skillOverrideChain.js +31 -4
- package/dist/skillsWireCaps.d.ts +16 -2
- package/dist/skillsWireCaps.js +47 -20
- package/dist/subagent/agentStateDetail.js +32 -8
- package/dist/subagent/engineCompactWire.js +48 -36
- package/dist/subagent/engineDelegatedPrompt.d.ts +3 -2
- package/dist/subagent/engineDelegatedPrompt.js +65 -28
- package/dist/subagentEditOutcomes.d.ts +9 -0
- package/dist/subagentEditOutcomes.js +43 -0
- package/dist/supportFloor.d.ts +2 -1
- package/dist/supportFloor.js +1 -1
- package/dist/toolResult.js +4 -2
- package/dist/toolRoster.d.ts +1 -0
- package/dist/toolRoster.js +1 -0
- package/dist/usageAnalytics.js +2 -1
- package/dist/userAttachmentEnvelope.d.ts +11 -0
- package/dist/userAttachmentEnvelope.js +7 -2
- package/dist/userAttachmentSeat.d.ts +7 -1
- package/dist/userAttachmentSeat.js +44 -7
- package/dist/wiringInstructionsAttribution.js +8 -2
- package/docs/INTEGRATION-CLIENTS.md +1588 -16
- package/package.json +5 -5
|
@@ -6,6 +6,8 @@ import { type ApprovalAllowRuleShadow } from './allowRuleShadow.js';
|
|
|
6
6
|
import { CORE_PERSISTED_RULE_MATCHES } from '../generated/engineFactTables.js';
|
|
7
7
|
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
8
8
|
import type { SessionRuleInertReason } from './sessionPolicyWire.js';
|
|
9
|
+
import type { LegacyToolApprovalFrame, LegacyToolApprovalRespondAck, LegacyToolApprovalRespondApplied, LegacyToolApprovalRespondReplayed } from './legacyApprovalShapes.js';
|
|
10
|
+
import { type ApprovalDecisionDoorReading, type AskDoorDecisionBody } from './approvalDecisionDoor.js';
|
|
9
11
|
import { type ApprovalCardClaim } from './approvalHolds.js';
|
|
10
12
|
import { type ApprovalResolution } from './approvalResolution.js';
|
|
11
13
|
import { type HostWithdrawal } from './hostWithdrawal.js';
|
|
@@ -15,7 +17,7 @@ import { type ApprovalDecidedByReading } from '../approvalDecidedByCapability.js
|
|
|
15
17
|
import { type PolicyDenyCause } from './policyDenyCause.js';
|
|
16
18
|
import { type ApprovalRequestFrameReading, type ApprovalRequestFrameUnreadableWhy } from './approvalRequestFrameReading.js';
|
|
17
19
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS } from '@sema-agent/sdk';
|
|
18
|
-
import type { ApprovalDecidedBy, ApprovalCardDelegation,
|
|
20
|
+
import type { ApprovalDecidedBy, ApprovalCardDelegation, PersistedRuleAnchor, RuleOfferMatch, RuleOfferBatchMember, RuleOfferUncoveredDetail, RuleOfferUncoveredReason, AskOrigin, RuleOffersAbsence, DenialLimitKind, DenialLimitFallback, ApprovalRequestFrame, RuleOffer as SdkRuleOffer } from '@sema-agent/sdk';
|
|
19
21
|
export declare function toolNameIsFsWrite(name: string): boolean;
|
|
20
22
|
export declare function toolNameIsShellExec(name: string): boolean;
|
|
21
23
|
export interface ToolApprovalGateLike {
|
|
@@ -183,13 +185,15 @@ export declare function surfaceApprovalCard(req: ApprovalCardRequest): Promise<A
|
|
|
183
185
|
declare const REMEMBER_REFUSAL_CODES: readonly ["remember_not_in_proof", "capability.store_required", "decide.workflow_remember_unsupported", "decide.parked_remember_unsupported", "remember_requires_binding"];
|
|
184
186
|
export type RememberRefusalCode = (typeof REMEMBER_REFUSAL_CODES)[number];
|
|
185
187
|
export declare function rememberRefusalOf(error: unknown): RememberRefusalCode | undefined;
|
|
188
|
+
export declare const FEEDBACK_REFUSAL_CODES: readonly ["feedback_not_in_proof"];
|
|
189
|
+
export declare function feedbackRefusalOf(error: unknown): boolean;
|
|
186
190
|
export declare function surfaceFsApprovalAndDecide(deps: FsApprovalWireDeps, taskId: string, argsByCall: Map<string, unknown>, signal?: AbortSignal, parkGatedCallId?: string, parkToolName?: string): Promise<ApprovalResolution>;
|
|
187
191
|
export interface BoundSkillGrantsWire {
|
|
188
192
|
readonly skill: string | null;
|
|
189
193
|
readonly allowedTools: readonly string[];
|
|
190
194
|
readonly disallowedTools: readonly string[];
|
|
191
195
|
}
|
|
192
|
-
export type {
|
|
196
|
+
export type { LegacyToolApprovalFrame, LegacyToolApprovalRespondAck };
|
|
193
197
|
export interface ReadRootCandidateView {
|
|
194
198
|
dir: string;
|
|
195
199
|
clearsThisAsk: true;
|
|
@@ -208,8 +212,8 @@ export declare function readApprovalMandate(v: {
|
|
|
208
212
|
} | undefined | null): ApprovalMandateWord | undefined;
|
|
209
213
|
export { readApprovalCardWord };
|
|
210
214
|
export declare function toolPermissionRequestAskBits(card: object | null | undefined, requestId?: string): Pick<ToolPermissionRequest, 'mandated' | 'mandate' | 'origin' | 'ruleOffersAbsence' | 'askClass' | 'classes' | 'sessionRow' | 'probeReason' | 'probeCause' | 'feedbackCapable' | 'requestedBy' | 'frameReading' | 'inputSource'>;
|
|
211
|
-
export declare function isFromSubagent(frame:
|
|
212
|
-
export type ToolApprovalRespondDecision =
|
|
215
|
+
export declare function isFromSubagent(frame: LegacyToolApprovalFrame): boolean;
|
|
216
|
+
export type ToolApprovalRespondDecision = (typeof RESPOND_DECISIONS)[number];
|
|
213
217
|
export declare const RESPOND_DECISIONS: readonly ["allow", "allow_session", "deny"];
|
|
214
218
|
export type AnswerPayloadLane = 'respond' | 'decide';
|
|
215
219
|
export interface AnswerPayloadCaps {
|
|
@@ -259,8 +263,8 @@ export interface RespondToolApprovalOpts {
|
|
|
259
263
|
settledBy?: 'policy';
|
|
260
264
|
decidedBy?: Extract<ApprovalDecidedBy, 'policy'>;
|
|
261
265
|
}
|
|
262
|
-
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<
|
|
263
|
-
export type ToolApprovalRespondAckView =
|
|
266
|
+
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<LegacyToolApprovalRespondAck | void>;
|
|
267
|
+
export type ToolApprovalRespondAckView = LegacyToolApprovalRespondAck | ToolApprovalRespondRedeemedView;
|
|
264
268
|
export interface ToolApprovalRespondRedeemedView {
|
|
265
269
|
readonly approvalId: string;
|
|
266
270
|
readonly askId: string;
|
|
@@ -269,12 +273,24 @@ export interface ToolApprovalRespondRedeemedView {
|
|
|
269
273
|
readonly decision?: string;
|
|
270
274
|
readonly rememberApplied?: boolean;
|
|
271
275
|
}
|
|
272
|
-
export declare function isToolApprovalRespondReplayed(ack: ToolApprovalRespondAckView): ack is
|
|
276
|
+
export declare function isToolApprovalRespondReplayed(ack: ToolApprovalRespondAckView): ack is LegacyToolApprovalRespondReplayed;
|
|
273
277
|
export declare function isToolApprovalRespondParkedRedeemed(ack: object): ack is ToolApprovalRespondRedeemedView;
|
|
274
278
|
export declare function replayedFirstDecisionOf(ack: ToolApprovalRespondAckView | undefined): 'allow' | 'deny' | undefined;
|
|
275
279
|
export declare function settlementAckOf(read: ToolApprovalRespondAckView | undefined): ToolApprovalRespondAckView | undefined;
|
|
276
280
|
export type { PersistedRuleAnchor };
|
|
277
281
|
export declare function readToolApprovalRespondAck(v: unknown): ToolApprovalRespondAckView | undefined;
|
|
282
|
+
export type AskDoorDecisionBodyReading = {
|
|
283
|
+
readonly kind: 'receipt';
|
|
284
|
+
readonly ack: LegacyToolApprovalRespondApplied;
|
|
285
|
+
} | {
|
|
286
|
+
readonly kind: 'earlier';
|
|
287
|
+
readonly firstDecision: 'allow' | 'deny';
|
|
288
|
+
} | {
|
|
289
|
+
readonly kind: 'other_ask';
|
|
290
|
+
} | {
|
|
291
|
+
readonly kind: 'none';
|
|
292
|
+
};
|
|
293
|
+
export declare function readAskDoorDecisionBody(v: {} | null | undefined, askId: string, sent: ToolApprovalRespondDecision): AskDoorDecisionBodyReading;
|
|
278
294
|
export interface ToolApprovalRespondParkingView {
|
|
279
295
|
readonly approvalId: string;
|
|
280
296
|
readonly retryAfterMs?: number;
|
|
@@ -312,7 +328,7 @@ export declare function decisionAttributionKeyOf(reading: ApprovalDecidedByReadi
|
|
|
312
328
|
} | {
|
|
313
329
|
settledBy: 'policy';
|
|
314
330
|
} | Record<never, never>;
|
|
315
|
-
export declare function isToolApprovalFrame(ev: unknown): ev is
|
|
331
|
+
export declare function isToolApprovalFrame(ev: unknown): ev is LegacyToolApprovalFrame;
|
|
316
332
|
export declare function askProbeReasonDetail(card: Pick<ApprovalCardRequest, 'probeReason' | 'probeCause'> | null | undefined, lang?: UiLanguage): string | undefined;
|
|
317
333
|
export declare function readApprovalRememberRefused(v: unknown): boolean;
|
|
318
334
|
export declare function readApprovalBoundGrants(v: unknown): BoundSkillGrantsWire | undefined;
|
|
@@ -332,6 +348,10 @@ export declare function approvalSupersedesDetail(card: Pick<ApprovalCardRequest,
|
|
|
332
348
|
export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
|
|
333
349
|
export declare function readRuleOffers(v: unknown): RuleOfferReading[] | undefined;
|
|
334
350
|
export declare function readRuleOfferSupply(offers: unknown): RuleOfferReading[] | undefined;
|
|
351
|
+
export declare function subagentBadgeFor(carrier: object | null | undefined): {
|
|
352
|
+
name: string;
|
|
353
|
+
color: string;
|
|
354
|
+
};
|
|
335
355
|
export type ApprovalCardV1Facts = Pick<ApprovalCardRequest, 'toolName' | 'args'> & Pick<ApprovalCardRequest, 'toolCallId' | 'workerBadge' | 'wireNote' | 'argsUnavailable' | 'inputSource' | 'governanceForced' | 'delegation' | 'ruleOffersReadOnly' | 'inputHasBidi' | 'allowRuleShadow' | 'probeCause' | 'rememberRefused' | 'ruleEvidence' | 'requiresRealApproval' | 'ruleOffersAbsence' | 'denialLimitFallback' | 'askClass' | 'classes' | 'agentId' | 'askReasons' | 'grantBinding' | 'unreadableEvidence' | 'message' | 'approvalCard'>;
|
|
336
356
|
export type ApprovalCardFacts = ApprovalCardV1Facts & Pick<ApprovalCardRequest, 'argsRewritten' | 'ruleOffers' | 'probeReason' | 'mandated' | 'mandate' | 'readRootCandidate' | 'origin' | 'boundGrants' | 'classifierNoRuling' | 'allowSessionCarried' | 'cardPayloadUnreadable' | 'cardPayloadUnreadableWhy' | 'requestedBy'>;
|
|
337
357
|
export interface ApprovalCardFrameFactsOptions {
|
|
@@ -349,6 +369,7 @@ export interface ToolApprovalFrameLaneOpts {
|
|
|
349
369
|
respondFreeFormRulesCapable?: boolean;
|
|
350
370
|
respondBatchRuleOffersCapable?: boolean;
|
|
351
371
|
approvalDecidedBy?: ApprovalDecidedByReading | undefined;
|
|
372
|
+
approvalDecisionDoor?: ApprovalDecisionDoorReading | undefined;
|
|
352
373
|
windowIsCurrent?: boolean;
|
|
353
374
|
argsUnavailable?: true;
|
|
354
375
|
}
|
|
@@ -357,8 +378,11 @@ export interface ToolApprovalFrameRunBits {
|
|
|
357
378
|
readonly sessionId?: string;
|
|
358
379
|
readonly sourceGeneration?: number;
|
|
359
380
|
}
|
|
360
|
-
export declare function surfaceToolApprovalFrameAndRespond(frame:
|
|
361
|
-
export declare function surfaceApprovalFrameWithId(frame:
|
|
381
|
+
export declare function surfaceToolApprovalFrameAndRespond(frame: LegacyToolApprovalFrame | ApprovalRequestFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts, run?: ToolApprovalFrameRunBits): Promise<ApprovalResolution>;
|
|
382
|
+
export declare function surfaceApprovalFrameWithId(frame: LegacyToolApprovalFrame | ApprovalRequestFrame, approvalId: string, respond: RespondToolApprovalFn, streamArgs: Parameters<typeof surfaceToolApprovalFrameAndRespond>[2], signal: AbortSignal | undefined, lane: ToolApprovalFrameLaneOpts | undefined, run: ToolApprovalFrameRunBits | undefined): Promise<ApprovalResolution>;
|
|
383
|
+
export declare function askDoorBodyOf(decision: ToolApprovalRespondDecision, o: RespondToolApprovalOpts, askId: string): AskDoorDecisionBody & {
|
|
384
|
+
readonly settledBy?: 'policy';
|
|
385
|
+
};
|
|
362
386
|
export interface ApprovalHolderIdentity {
|
|
363
387
|
readonly approvalId?: string;
|
|
364
388
|
readonly taskId?: string;
|
|
@@ -22,7 +22,8 @@ import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
|
22
22
|
import { displayUntrusted, quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
23
23
|
import { frameBindingOf } from '../frameBinding.js';
|
|
24
24
|
import { carriesAttributionKey, deliverWithAttributionLadder } from './attributionLadder.js';
|
|
25
|
-
import { deliverApprovalDecision, newSendTally } from './approvalDelivery.js';
|
|
25
|
+
import { askDoorParkingOfThrown, deliverApprovalDecision, isAborted, newSendTally, respondRouteGoneOf } from './approvalDelivery.js';
|
|
26
|
+
import { approvalDecisionDoorOf, approvalDecisionVerbOf, hitlAskIdempotencyKey, noteRespondDoorSwitch, ROUTE_MISSING_WIRING_HINT } from './approvalDecisionDoor.js';
|
|
26
27
|
import { approvalDecisionHolds, approvalHoldFor, awaitApprovalHolder, claimApprovalCardFor, enterLiveRespondPhase, holdLiveCard, joinLiveCard, liveCardHoldOf, clearSettledApprovals, noteHolderSettledApproval, settledApprovalOf, settledForDurableLane, settledLiveCardOutcome } from './approvalHolds.js';
|
|
27
28
|
import { directFailureVerdictOf, directSafetyStopOf, joinedResolution, resolutionOfDecisionFailure, toolPermissionSettledElsewhereOf } from './approvalResolution.js';
|
|
28
29
|
import { hostWithdrawalOf } from './hostWithdrawal.js';
|
|
@@ -186,8 +187,8 @@ export function rememberRefusalOf(error) {
|
|
|
186
187
|
function rememberRefusalIn(reading) {
|
|
187
188
|
return reading.state === 'code' ? REMEMBER_REFUSAL_CODES.find((c) => c === reading.code) : undefined;
|
|
188
189
|
}
|
|
189
|
-
const FEEDBACK_REFUSAL_CODES = Object.freeze(['feedback_not_in_proof']);
|
|
190
|
-
function feedbackRefusalOf(error) {
|
|
190
|
+
export const FEEDBACK_REFUSAL_CODES = Object.freeze(['feedback_not_in_proof']);
|
|
191
|
+
export function feedbackRefusalOf(error) {
|
|
191
192
|
const reading = readWireErrorCodeReading(error);
|
|
192
193
|
return reading.state === 'code' && FEEDBACK_REFUSAL_CODES.some((c) => c === reading.code);
|
|
193
194
|
}
|
|
@@ -863,8 +864,6 @@ export function isFromSubagent(frame) {
|
|
|
863
864
|
return frame.fromSubagent === true;
|
|
864
865
|
}
|
|
865
866
|
export const RESPOND_DECISIONS = Object.freeze(['allow', 'allow_session', 'deny']);
|
|
866
|
-
const _respondDecisionPins = [true, true];
|
|
867
|
-
void _respondDecisionPins;
|
|
868
867
|
function isRespondDecision(v) {
|
|
869
868
|
return typeof v === 'string' && RESPOND_DECISIONS.includes(v);
|
|
870
869
|
}
|
|
@@ -985,6 +984,9 @@ export function readToolApprovalRespondAck(v) {
|
|
|
985
984
|
return undefined;
|
|
986
985
|
if (!isRespondDecision(decision))
|
|
987
986
|
return undefined;
|
|
987
|
+
return appliedReceiptOf(s, approvalId, decision);
|
|
988
|
+
}
|
|
989
|
+
function appliedReceiptOf(s, approvalId, decision) {
|
|
988
990
|
const rememberApplied = slotValueOf(s.rememberApplied);
|
|
989
991
|
const updatedInputForwarded = slotValueOf(s.updatedInputForwarded);
|
|
990
992
|
const rulePersisted = slotValueOf(s.rulePersisted);
|
|
@@ -996,7 +998,7 @@ export function readToolApprovalRespondAck(v) {
|
|
|
996
998
|
const out = {
|
|
997
999
|
approvalId,
|
|
998
1000
|
delivery: 'applied',
|
|
999
|
-
decision
|
|
1001
|
+
decision,
|
|
1000
1002
|
...(typeof rememberApplied === 'boolean' ? { rememberApplied } : {}),
|
|
1001
1003
|
...(typeof updatedInputForwarded === 'boolean' ? { updatedInputForwarded } : {}),
|
|
1002
1004
|
...(typeof rulePersisted === 'boolean' ? { rulePersisted } : {}),
|
|
@@ -1027,6 +1029,26 @@ export function readToolApprovalRespondAck(v) {
|
|
|
1027
1029
|
}
|
|
1028
1030
|
return out;
|
|
1029
1031
|
}
|
|
1032
|
+
export function readAskDoorDecisionBody(v, askId, sent) {
|
|
1033
|
+
if (v === null || typeof v !== 'object')
|
|
1034
|
+
return Object.freeze({ kind: 'none' });
|
|
1035
|
+
const s = respondAckSlotsOf(v);
|
|
1036
|
+
const want = sent === 'deny' ? 'deny' : 'approve';
|
|
1037
|
+
const idOk = typeof askId === 'string' && askId !== '' && slotValueOf(s.askId) === askId;
|
|
1038
|
+
const dec = slotValueOf(s.decision);
|
|
1039
|
+
if (s.askId.presence !== 'absent' && !idOk)
|
|
1040
|
+
return Object.freeze({ kind: 'other_ask' });
|
|
1041
|
+
if (s.decision.presence !== 'absent' && dec !== want) {
|
|
1042
|
+
return idOk && (dec === 'approve' || dec === 'deny') ? Object.freeze({ kind: 'earlier', firstDecision: dec === 'approve' ? 'allow' : 'deny' }) : Object.freeze({ kind: 'other_ask' });
|
|
1043
|
+
}
|
|
1044
|
+
if (s.accepted.presence !== 'absent' || s.idempotent.presence !== 'absent' || s.delivery.presence !== 'absent')
|
|
1045
|
+
return Object.freeze({ kind: 'none' });
|
|
1046
|
+
if (idOk && dec === want) {
|
|
1047
|
+
const ack = appliedReceiptOf(s, askId, sent);
|
|
1048
|
+
return ack !== undefined ? Object.freeze({ kind: 'receipt', ack }) : Object.freeze({ kind: 'none' });
|
|
1049
|
+
}
|
|
1050
|
+
return Object.freeze({ kind: 'none' });
|
|
1051
|
+
}
|
|
1030
1052
|
const RESPOND_ACK_SLOT_KEYS = [
|
|
1031
1053
|
'accepted',
|
|
1032
1054
|
'idempotent',
|
|
@@ -1120,6 +1142,7 @@ function ownIdempotentTrue(raw) {
|
|
|
1120
1142
|
return false;
|
|
1121
1143
|
}
|
|
1122
1144
|
}
|
|
1145
|
+
const REPLAY_NONE = Object.freeze({ kind: 'none' });
|
|
1123
1146
|
export function replayVerdictFrom(raw, parsed, approvalId) {
|
|
1124
1147
|
if (parsed !== undefined && isToolApprovalRespondReplayed(parsed) && parsed.approvalId === approvalId)
|
|
1125
1148
|
return { kind: 'replayed', firstDecision: parsed.decision, via: 'arm' };
|
|
@@ -1506,7 +1529,7 @@ const UNREADABLE_EVIDENCE_KEYS = Object.freeze({
|
|
|
1506
1529
|
]),
|
|
1507
1530
|
v1: Object.freeze([
|
|
1508
1531
|
['rememberRefused', 'rememberRefused'], ['governanceForced', 'governanceForced'], ['requiresRealApproval', 'requiresRealApproval'],
|
|
1509
|
-
['ruleOffersAbsence', 'ruleOffersAbsence'], ['ruleOffers', 'ruleOffersReadOnly'],
|
|
1532
|
+
['ruleOffersAbsence', 'ruleOffersAbsence'], ['ruleOffers', ['ruleOffersReadOnly', 'ruleOffers']],
|
|
1510
1533
|
['allowRuleShadowed', 'allowRuleShadow'], ['askClass', 'askClass'], ['classes', 'classes'],
|
|
1511
1534
|
]),
|
|
1512
1535
|
generic: Object.freeze([['ruleOffersAbsence', 'ruleOffersAbsence'], ['askClass', 'askClass'], ['classes', 'classes']]),
|
|
@@ -1525,7 +1548,8 @@ function riskSubtreeUnreadable(card) {
|
|
|
1525
1548
|
function withUnreadableEvidence(carrier, leg, req, reported = [], live) {
|
|
1526
1549
|
const keys = new Set(reported);
|
|
1527
1550
|
for (const [from, to] of UNREADABLE_EVIDENCE_KEYS[leg]) {
|
|
1528
|
-
|
|
1551
|
+
const read = typeof to === 'string' ? Object.hasOwn(req, to) : to.some((t) => Object.hasOwn(req, t));
|
|
1552
|
+
if (slotPresenceOf(carrier, from) !== 'absent' && !read)
|
|
1529
1553
|
keys.add(from);
|
|
1530
1554
|
}
|
|
1531
1555
|
if (live !== undefined) {
|
|
@@ -1715,6 +1739,7 @@ function noteCallOutcome(slot, r) {
|
|
|
1715
1739
|
const unsettledFate = {
|
|
1716
1740
|
engine_refused: 'not_accepted',
|
|
1717
1741
|
parking_in_progress: 'not_accepted',
|
|
1742
|
+
route_missing: 'not_accepted',
|
|
1718
1743
|
engine_error: 'unconfirmed',
|
|
1719
1744
|
no_answer: 'unconfirmed',
|
|
1720
1745
|
transport_exhausted: 'unconfirmed',
|
|
@@ -1921,17 +1946,18 @@ export function readRuleOffers(v) {
|
|
|
1921
1946
|
export function readRuleOfferSupply(offers) {
|
|
1922
1947
|
return readRuleOffers(offers);
|
|
1923
1948
|
}
|
|
1924
|
-
function subagentBadgeFor(
|
|
1925
|
-
let name =
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1949
|
+
export function subagentBadgeFor(carrier) {
|
|
1950
|
+
let name = guardedRead(() => readOwnDataNonEmptyString(carrier, 'sourceAgentName')) ?? '';
|
|
1951
|
+
if (!name) {
|
|
1952
|
+
const agentId = approvalAgentIdOf(carrier);
|
|
1953
|
+
if (agentId !== undefined) {
|
|
1954
|
+
try {
|
|
1955
|
+
const row = readEngineActiveBgTasks().tasks.find(t => t.id === agentId);
|
|
1956
|
+
if (typeof row?.name === 'string' && row.name.length > 0)
|
|
1957
|
+
name = row.name;
|
|
1958
|
+
}
|
|
1959
|
+
catch {
|
|
1960
|
+
}
|
|
1935
1961
|
}
|
|
1936
1962
|
}
|
|
1937
1963
|
if (!name)
|
|
@@ -2011,7 +2037,7 @@ function v1Bit(stamp) {
|
|
|
2011
2037
|
const SUSPENDED_ASK_ARGS_NOTE = "this request's tool arguments are not available on this surface — it was raised while no client was connected, " +
|
|
2012
2038
|
'so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
|
|
2013
2039
|
'Edits are not accepted on this card: there is no original input to edit';
|
|
2014
|
-
function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
2040
|
+
function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy, rulesRedeemable) {
|
|
2015
2041
|
const c = carrier;
|
|
2016
2042
|
const full = leg !== 'generic';
|
|
2017
2043
|
const live = leg === 'frame' ? carrier : leg === 'v1' ? liveFacts : undefined;
|
|
@@ -2093,7 +2119,7 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
2093
2119
|
const offers = readRuleOffers(c.ruleOffers);
|
|
2094
2120
|
if (offers === undefined)
|
|
2095
2121
|
return;
|
|
2096
|
-
if (leg === 'frame')
|
|
2122
|
+
if (leg === 'frame' || (leg === 'v1' && rulesRedeemable === true))
|
|
2097
2123
|
out.ruleOffers = offers;
|
|
2098
2124
|
else
|
|
2099
2125
|
out.ruleOffersReadOnly = offers;
|
|
@@ -2263,12 +2289,95 @@ export async function surfaceApprovalFrameWithId(frame, approvalId, respond, str
|
|
|
2263
2289
|
if (typeof approvalId !== 'string' || approvalId === '')
|
|
2264
2290
|
return approvalIdUnreadableRefusal();
|
|
2265
2291
|
const carriers = openingFrameCarriersOf(frame);
|
|
2292
|
+
const route = askDoorRouteOf(lane, carriers, frame, approvalId, respond);
|
|
2293
|
+
if (route.kind === 'refused')
|
|
2294
|
+
return route.resolution;
|
|
2266
2295
|
const liveRun = liveCardRunOf(frame, run);
|
|
2267
2296
|
const sourceGenerationRaw = guardedRead(() => readOwnDataValue(run, 'sourceGeneration'));
|
|
2268
2297
|
const sourceGeneration = typeof sourceGenerationRaw === 'number' && Number.isFinite(sourceGenerationRaw) ? sourceGenerationRaw : undefined;
|
|
2269
|
-
const
|
|
2298
|
+
const askDoor = route.kind === 'target' ? route.target : undefined;
|
|
2299
|
+
const respondSwitch = route.kind === 'respond' ? route.switchTo : undefined;
|
|
2300
|
+
const entry = { frame, carriers, approvalId, identity: liveCardIdentityOf(approvalId, carriers, liveRun), respond, streamArgs, signal, lane, receivedAtMs, sourceGeneration, askDoor, respondSwitch };
|
|
2270
2301
|
return enterLiveCard(entry);
|
|
2271
2302
|
}
|
|
2303
|
+
const RESPOND_ROUTE = Object.freeze({ kind: 'respond' });
|
|
2304
|
+
function askDoorRouteOf(lane, carriers, frame, approvalId, respond) {
|
|
2305
|
+
const reading = guardedRead(() => readOwnDataValue(lane, 'approvalDecisionDoor'));
|
|
2306
|
+
const door = approvalDecisionDoorOf(reading);
|
|
2307
|
+
const refused = (cause, missing) => {
|
|
2308
|
+
const resolution = missing !== undefined ? { kind: 'not_sent', lane: 'respond', cause, door: missing } : { kind: 'not_sent', lane: 'respond', cause };
|
|
2309
|
+
return Object.freeze({ kind: 'refused', resolution });
|
|
2310
|
+
};
|
|
2311
|
+
let target;
|
|
2312
|
+
if (door === 'ask_decision') {
|
|
2313
|
+
const blindRow = guardedRead(() => readOwnDataValue(lane, 'argsUnavailable')) === true;
|
|
2314
|
+
const t = askDoorTargetOf(reading, carriers, frame, approvalId, blindRow);
|
|
2315
|
+
if (t === 'card_unavailable' || t === 'card_unreadable')
|
|
2316
|
+
return refused(t);
|
|
2317
|
+
target = t;
|
|
2318
|
+
}
|
|
2319
|
+
if (door === 'ask_decision' ? target === undefined : typeof respond !== 'function') {
|
|
2320
|
+
hostLog('error', door === 'ask_decision'
|
|
2321
|
+
? `liveToolApprovalWire: ${approvalId} must be answered on the ask decision door, but this host has not wired that door (approvalDecisionDoor.verbs.decideAsk) — not raised as a card, nothing sent; the request is still waiting on the engine`
|
|
2322
|
+
: `liveToolApprovalWire: ${approvalId} must be answered on the respond door (the server is below the ask decision door version, or its version is unreadable), but the respond port this host passed is not a function — not raised as a card, nothing sent; the request is still waiting on the engine`);
|
|
2323
|
+
return refused('no_verb', door);
|
|
2324
|
+
}
|
|
2325
|
+
if (target !== undefined)
|
|
2326
|
+
return Object.freeze({ kind: 'target', target });
|
|
2327
|
+
const addr = askDoorAddressOf(carriers, frame, approvalId);
|
|
2328
|
+
const decide = 'missing' in addr ? undefined : approvalDecisionVerbOf(reading);
|
|
2329
|
+
if ('missing' in addr || decide === undefined)
|
|
2330
|
+
return RESPOND_ROUTE;
|
|
2331
|
+
return Object.freeze({ kind: 'respond', switchTo: Object.freeze({ target: Object.freeze({ taskId: addr.taskId, askId: addr.askId, decide }), reading }) });
|
|
2332
|
+
}
|
|
2333
|
+
function askDoorAddressOf(carriers, frame, approvalId) {
|
|
2334
|
+
if (carriers.leg === 'frame')
|
|
2335
|
+
return { missing: 'old_family' };
|
|
2336
|
+
const askId = guardedRead(() => readOwnDataNonEmptyString(frame, 'askId'));
|
|
2337
|
+
const taskId = guardedRead(() => readOwnDataNonEmptyString(frame, 'taskId'));
|
|
2338
|
+
if (askId === undefined)
|
|
2339
|
+
return { missing: 'askId' };
|
|
2340
|
+
if (taskId === undefined)
|
|
2341
|
+
return { missing: 'taskId' };
|
|
2342
|
+
if (askId !== approvalId)
|
|
2343
|
+
return { missing: 'mismatch' };
|
|
2344
|
+
return { taskId, askId };
|
|
2345
|
+
}
|
|
2346
|
+
function askDoorTargetOf(reading, carriers, frame, approvalId, blindRow) {
|
|
2347
|
+
const addr = askDoorAddressOf(carriers, frame, approvalId);
|
|
2348
|
+
if ('missing' in addr) {
|
|
2349
|
+
if (addr.missing === 'old_family' && blindRow) {
|
|
2350
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} is a pending row whose card this host could not read, on a server that only takes the ask decision door — not raised as a card, nothing sent`);
|
|
2351
|
+
return 'card_unreadable';
|
|
2352
|
+
}
|
|
2353
|
+
if (addr.missing === 'old_family') {
|
|
2354
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} is an old-family approval frame on a server that only takes the ask decision door — not raised as a card, nothing sent`);
|
|
2355
|
+
return 'card_unavailable';
|
|
2356
|
+
}
|
|
2357
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} has no usable ask identity on its frame (${addr.missing === 'mismatch' ? 'askId differs from the approval id' : addr.missing}) — the ask decision door cannot be addressed; not raised as a card, nothing sent`);
|
|
2358
|
+
return 'card_unavailable';
|
|
2359
|
+
}
|
|
2360
|
+
const decide = approvalDecisionVerbOf(reading);
|
|
2361
|
+
return decide === undefined ? undefined : Object.freeze({ taskId: addr.taskId, askId: addr.askId, decide });
|
|
2362
|
+
}
|
|
2363
|
+
export function askDoorBodyOf(decision, o, askId) {
|
|
2364
|
+
const verdict = decision === 'deny' ? 'deny' : 'approve';
|
|
2365
|
+
const persistRule = o.persistRuleBatchOfferIndex !== undefined
|
|
2366
|
+
? { batchOfferIndex: o.persistRuleBatchOfferIndex }
|
|
2367
|
+
: o.persistRule !== undefined
|
|
2368
|
+
? { rule: o.persistRule, ...(o.persistRuleEdited === true ? { edited: true } : {}) }
|
|
2369
|
+
: undefined;
|
|
2370
|
+
return {
|
|
2371
|
+
decision: verdict,
|
|
2372
|
+
idempotencyKey: hitlAskIdempotencyKey(askId, verdict),
|
|
2373
|
+
...(decision === 'allow_session' ? { remember: 'session' } : {}),
|
|
2374
|
+
...(verdict === 'approve' && o.updatedInput !== undefined ? { updatedInput: o.updatedInput } : {}),
|
|
2375
|
+
...(o.note !== undefined ? { note: o.note } : {}),
|
|
2376
|
+
...(verdict === 'approve' && persistRule !== undefined ? { persistRule } : {}),
|
|
2377
|
+
...(o.decidedBy !== undefined ? { decidedBy: o.decidedBy } : {}),
|
|
2378
|
+
...(o.settledBy !== undefined ? { settledBy: o.settledBy } : {}),
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2272
2381
|
function openingFrameCarriersOf(frame) {
|
|
2273
2382
|
if (frame.type !== 'approval_request')
|
|
2274
2383
|
return { body: frame, live: frame, leg: 'frame' };
|
|
@@ -2292,7 +2401,7 @@ function enterLiveCard(e) {
|
|
|
2292
2401
|
return joinOtherLaneHolder(e, other);
|
|
2293
2402
|
return holdLiveCard(e.identity, signal, async (hold) => {
|
|
2294
2403
|
const slot = {};
|
|
2295
|
-
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs, e.identity.taskId, e.sourceGeneration);
|
|
2404
|
+
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs, e.identity.taskId, e.sourceGeneration, e.askDoor, e.respondSwitch);
|
|
2296
2405
|
noteCallOutcome(slot, out);
|
|
2297
2406
|
return out;
|
|
2298
2407
|
});
|
|
@@ -2376,11 +2485,12 @@ function readApprovalCardClaimSignal(v) {
|
|
|
2376
2485
|
export function claimApprovalCard(identity, options) {
|
|
2377
2486
|
return claimApprovalCardFor(readApprovalHolderIdentity(identity), readApprovalCardClaimSignal(options));
|
|
2378
2487
|
}
|
|
2379
|
-
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId, sourceGeneration) {
|
|
2488
|
+
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId, sourceGeneration, entryAskDoor, respondSwitch) {
|
|
2489
|
+
let askDoor = entryAskDoor;
|
|
2380
2490
|
const bodyToolCallId = carriers.body.toolCallId;
|
|
2381
2491
|
const frameToolCallId = typeof bodyToolCallId === 'string' && bodyToolCallId !== '' ? bodyToolCallId : undefined;
|
|
2382
2492
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
2383
|
-
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live, approvalId, carriers.why);
|
|
2493
|
+
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live, approvalId, carriers.why, askDoor !== undefined);
|
|
2384
2494
|
const argsNotRealInput = facts.argsUnavailable === true;
|
|
2385
2495
|
const editAcceptance = editedApprovalAcceptanceOf(facts);
|
|
2386
2496
|
const ruleOffers = facts.ruleOffers;
|
|
@@ -2416,16 +2526,36 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2416
2526
|
const p = readToolApprovalRespondParking(body);
|
|
2417
2527
|
return p?.kind === 'parking' ? p.view : undefined;
|
|
2418
2528
|
};
|
|
2419
|
-
const
|
|
2529
|
+
const noParkingBody = () => undefined;
|
|
2530
|
+
const parkingInProgress = (parking) => ({ kind: 'unsettled', lane: 'respond', cause: 'parking_in_progress', parking });
|
|
2531
|
+
const deliverVia = (door, d, body, carrySignal, deliverySignal, ladder, onLadderStep) => deliverApprovalDecision({
|
|
2420
2532
|
approvalId,
|
|
2421
2533
|
body,
|
|
2422
|
-
send: (o, sig) =>
|
|
2534
|
+
send: (o, sig) => door !== undefined
|
|
2535
|
+
? door.decide(door.taskId, door.askId, askDoorBodyOf(d, o, door.askId), carrySignal && sig !== undefined ? { signal: sig } : undefined)
|
|
2536
|
+
: respond(approvalId, d, carrySignal && sig !== undefined ? { ...o, signal: sig } : o),
|
|
2423
2537
|
signal: deliverySignal,
|
|
2424
2538
|
tally: newSendTally(),
|
|
2425
2539
|
ladder,
|
|
2426
2540
|
...(onLadderStep !== undefined ? { onLadderStep } : {}),
|
|
2427
|
-
parkingOf: respondParkingOf,
|
|
2541
|
+
parkingOf: door !== undefined ? noParkingBody : respondParkingOf,
|
|
2542
|
+
...(door !== undefined ? { parkingOfThrown: (reading) => askDoorParkingOfThrown(reading, approvalId) } : {}),
|
|
2428
2543
|
});
|
|
2544
|
+
const deliverOnThisCard = (d, body, carrySignal, deliverySignal, ladder, onLadderStep) => {
|
|
2545
|
+
const first = deliverVia(askDoor, d, body, carrySignal, deliverySignal, ladder, onLadderStep);
|
|
2546
|
+
const sw = respondSwitch;
|
|
2547
|
+
if (askDoor !== undefined || sw === undefined)
|
|
2548
|
+
return first;
|
|
2549
|
+
return first.then((delivery) => {
|
|
2550
|
+
if (delivery.kind !== 'thrown' || !respondRouteGoneOf(delivery))
|
|
2551
|
+
return delivery;
|
|
2552
|
+
noteRespondDoorSwitch(sw.reading, 'liveToolApprovalWire', approvalId);
|
|
2553
|
+
if (isAborted(deliverySignal))
|
|
2554
|
+
return delivery;
|
|
2555
|
+
askDoor = sw.target;
|
|
2556
|
+
return deliverVia(sw.target, d, body, carrySignal, deliverySignal, ladder, onLadderStep);
|
|
2557
|
+
});
|
|
2558
|
+
};
|
|
2429
2559
|
if (card.kind === 'aborted') {
|
|
2430
2560
|
enterLiveRespondPhase(hold);
|
|
2431
2561
|
const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
|
|
@@ -2579,7 +2709,7 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2579
2709
|
}
|
|
2580
2710
|
const attributionDropped = ladder.dropped;
|
|
2581
2711
|
const attributionRenamed = ladder.renamed;
|
|
2582
|
-
const parkingBody = readToolApprovalRespondParking(raw);
|
|
2712
|
+
const parkingBody = askDoor === undefined ? readToolApprovalRespondParking(raw) : undefined;
|
|
2583
2713
|
if (parkingBody !== undefined) {
|
|
2584
2714
|
const parking = parkingBody.kind === 'parking' && parkingBody.view.approvalId === approvalId ? parkingBody.view : undefined;
|
|
2585
2715
|
if (parking !== undefined) {
|
|
@@ -2588,14 +2718,23 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2588
2718
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered 202 parking_in_progress${hint !== undefined ? ` (retryAfterMs=${hint})` : ''} — ` +
|
|
2589
2719
|
`the answer did NOT take effect${decidePath !== undefined ? ' (the engine pointed at a decide path for the parked card)' : ''}; not reported as decided (the one invited re-send, if any, has already been made); the user is told to answer again on the parked card`);
|
|
2590
2720
|
surfaceApprovalParking(hint);
|
|
2591
|
-
return
|
|
2721
|
+
return parkingInProgress(parking);
|
|
2592
2722
|
}
|
|
2593
2723
|
hostLog('error', `liveToolApprovalWire: 202 parking body for ${approvalId} is ${parkingBody.kind === 'parking' ? `for another approval (${parkingBody.view.approvalId})` : 'unreadable (approvalId is not usable)'} — ` +
|
|
2594
2724
|
'reporting the answer as NOT settled (never as decided, never as parked); not re-sent');
|
|
2595
2725
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
2596
2726
|
}
|
|
2597
|
-
const
|
|
2598
|
-
|
|
2727
|
+
const askDoorBody = askDoor !== undefined ? readAskDoorDecisionBody(raw, askDoor.askId, decision) : undefined;
|
|
2728
|
+
if (askDoorBody?.kind === 'earlier') {
|
|
2729
|
+
hostLog('debug', `liveToolApprovalWire: decision(${decision}) for ${approvalId} answered with a body that names this ask but records the other decision (${askDoorBody.firstDecision}) — reporting the earlier decision, never the one this client sent`);
|
|
2730
|
+
return replayedDecisionOf(askDoorBody.firstDecision, decision);
|
|
2731
|
+
}
|
|
2732
|
+
if (askDoorBody?.kind === 'other_ask') {
|
|
2733
|
+
hostLog('error', `liveToolApprovalWire: decision(${decision}) for ${approvalId} answered with a body that names another ask or cannot be matched to this one — reporting the answer as NOT settled (never as the decision this client sent); not re-sent`);
|
|
2734
|
+
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
2735
|
+
}
|
|
2736
|
+
const parsed = askDoor !== undefined ? (askDoorBody?.kind === 'receipt' ? askDoorBody.ack : undefined) : settlementAckOf(readToolApprovalRespondAck(raw));
|
|
2737
|
+
const replayVerdict = askDoor === undefined ? replayVerdictFrom(raw, parsed, approvalId) : REPLAY_NONE;
|
|
2599
2738
|
if (replayVerdict.kind === 'replayed' && replayVerdict.via === 'claim') {
|
|
2600
2739
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay (body not in the full replay shape) — the approval was already decided ` +
|
|
2601
2740
|
`(${replayVerdict.firstDecision}); this answer was not delivered, reporting the earlier decision`);
|
|
@@ -2690,14 +2829,24 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2690
2829
|
}
|
|
2691
2830
|
catch (e) {
|
|
2692
2831
|
const fromDelivery = deliveryFailure !== undefined && deliveryFailure.error === e ? deliveryFailure : undefined;
|
|
2832
|
+
const askDoorParking = askDoor !== undefined && fromDelivery !== undefined ? askDoorParkingOfThrown(fromDelivery.reading, approvalId) : undefined;
|
|
2833
|
+
if (askDoorParking !== undefined) {
|
|
2834
|
+
const hint = ownReadingSlot(askDoorParking, 'retryAfterMs');
|
|
2835
|
+
hostLog('debug', `liveToolApprovalWire: decision(${decision}) for ${approvalId} answered 425 parking.ask_retry${hint !== undefined ? ` (retryAfterMs=${hint})` : ''} — the answer did NOT take effect; ` +
|
|
2836
|
+
'not reported as decided (the one invited re-send, if any, has already been made)');
|
|
2837
|
+
surfaceApprovalParking(hint);
|
|
2838
|
+
return parkingInProgress(askDoorParking);
|
|
2839
|
+
}
|
|
2693
2840
|
const r = resolutionOfDecisionFailure(e, {
|
|
2694
2841
|
lane: 'respond',
|
|
2695
|
-
route: 'live_respond',
|
|
2842
|
+
route: askDoor !== undefined ? 'ask_decide' : 'live_respond',
|
|
2696
2843
|
attributionCarried: lastSendCarriedAttribution,
|
|
2697
2844
|
...(fromDelivery?.transportExhausted === true ? { transportExhausted: true } : {}),
|
|
2698
2845
|
...(fromDelivery?.afterRetry === true ? { afterRetry: true } : {}),
|
|
2699
2846
|
...(fromDelivery !== undefined ? { delivered: fromDelivery.reading } : {}),
|
|
2700
2847
|
});
|
|
2848
|
+
if (r.kind === 'unsettled' && r.cause === 'route_missing' && askDoor === undefined && respondSwitch === undefined)
|
|
2849
|
+
hostLog('warn', ROUTE_MISSING_WIRING_HINT);
|
|
2701
2850
|
const refusal = r.kind === 'unsettled' ? r.refusal : undefined;
|
|
2702
2851
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) failed for ${approvalId} ` +
|
|
2703
2852
|
`(status=${refusal?.status ?? 'none'} errorCode=${logSafeErrorCode(refusal?.errorCode)} ` +
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
|
+
import { type HooksWireSettingsContract } from './pluginHooksWire.js';
|
|
2
3
|
export type HookMatcherUnjudgedReason = 'event_out_of_scope' | 'not_a_string' | 'oversize' | 'pattern_unsupported' | 'over_budget';
|
|
3
4
|
export type HookMatcherRefusedReason = 'alias_without_canonical' | 'invalid_regex';
|
|
4
5
|
export type HookMatcherVerdict = {
|
|
@@ -24,5 +25,5 @@ export type HookMatcherVerdict = {
|
|
|
24
25
|
readonly kind: 'unjudged';
|
|
25
26
|
readonly reason: HookMatcherUnjudgedReason;
|
|
26
27
|
};
|
|
27
|
-
export declare function hookMatcherVerdict(event: string, matcher: unknown): HookMatcherVerdict;
|
|
28
|
+
export declare function hookMatcherVerdict(event: string, matcher: unknown, contract: HooksWireSettingsContract): HookMatcherVerdict;
|
|
28
29
|
export declare function hookMatcherUnjudgedWhy(reason: HookMatcherUnjudgedReason | string, lang?: UiLanguage): string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
2
|
import { HOOK_TOOL_ALIASES } from './hookToolAliases.js';
|
|
3
3
|
import { SETTINGS_TOOL_NAME_MATCHER_EVENTS } from './generated/settingsSchemaTables.js';
|
|
4
|
+
import { isEngineFiredHookEvent } from './pluginHooksWire.js';
|
|
4
5
|
import { SETTINGS_HOOK_MATCHER_FORM, SETTINGS_HOOK_MATCHER_SELECTS } from './generated/settingsSchemaFns.js';
|
|
5
6
|
const TOOL_NAME_MATCHER_EVENTS = new Set(SETTINGS_TOOL_NAME_MATCHER_EVENTS);
|
|
6
7
|
const MATCHER_MAX_CHARS = 8192;
|
|
@@ -180,8 +181,8 @@ function patternBound(src, n) {
|
|
|
180
181
|
throw e;
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
|
-
export function hookMatcherVerdict(event, matcher) {
|
|
184
|
-
if (typeof event !== 'string' || !TOOL_NAME_MATCHER_EVENTS.has(event))
|
|
184
|
+
export function hookMatcherVerdict(event, matcher, contract) {
|
|
185
|
+
if (typeof event !== 'string' || !TOOL_NAME_MATCHER_EVENTS.has(event) || !isEngineFiredHookEvent(event, contract))
|
|
185
186
|
return unjudged('event_out_of_scope');
|
|
186
187
|
if (matcher !== undefined && typeof matcher !== 'string')
|
|
187
188
|
return unjudged('not_a_string');
|
|
@@ -1 +1,9 @@
|
|
|
1
|
+
import type { EngineCapValueState } from './engineCapsCache.js';
|
|
2
|
+
import { type HooksWireEngineFacts } from './pluginHooksWire.js';
|
|
1
3
|
export declare function hooksReaderNotReadKeys(serverVersion: string | undefined): readonly string[];
|
|
4
|
+
export type HookEntryFieldsReading = Exclude<HooksWireEngineFacts['hookEntryFields'], undefined>;
|
|
5
|
+
export interface HooksEntryKeyReader {
|
|
6
|
+
readonly fields: HookEntryFieldsReading;
|
|
7
|
+
readonly reads: (entryType: string, key: string, carriedByCopy: boolean) => boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function hooksEntryKeyReaderOf(settingsContract: EngineCapValueState, serverVersion: string | undefined): HooksEntryKeyReader;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ownDataField } from './ownKey.js';
|
|
2
|
+
import { HOOK_ENTRY_TYPE_WORDS } from './pluginHooksWire.js';
|
|
1
3
|
import { engineVersionTier } from './supportFloor.js';
|
|
2
4
|
const HOOKS_READER_GENERATIONS = Object.freeze([
|
|
3
5
|
Object.freeze({ from: '7.139.0', below: '7.147.0', notRead: Object.freeze(['onFailure', 'rewakeMessage', 'rewakeSummary', 'cloud', 'continueOnBlock']) }),
|
|
@@ -10,3 +12,50 @@ export function hooksReaderNotReadKeys(serverVersion) {
|
|
|
10
12
|
}
|
|
11
13
|
return HOOKS_READER_FAIL_CLOSED;
|
|
12
14
|
}
|
|
15
|
+
function isPlainRecord(v) {
|
|
16
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
17
|
+
}
|
|
18
|
+
function hookEntryFieldsOf(group) {
|
|
19
|
+
try {
|
|
20
|
+
if (!isPlainRecord(group))
|
|
21
|
+
return undefined;
|
|
22
|
+
const table = ownDataField(group, 'hookEntryFields');
|
|
23
|
+
if (!isPlainRecord(table))
|
|
24
|
+
return undefined;
|
|
25
|
+
const columns = Object.keys(table);
|
|
26
|
+
if (columns.length !== HOOK_ENTRY_TYPE_WORDS.length || !HOOK_ENTRY_TYPE_WORDS.every((t) => columns.includes(t)))
|
|
27
|
+
return undefined;
|
|
28
|
+
const out = new Map();
|
|
29
|
+
for (const type of HOOK_ENTRY_TYPE_WORDS) {
|
|
30
|
+
const column = ownDataField(table, type);
|
|
31
|
+
if (!Array.isArray(column))
|
|
32
|
+
return undefined;
|
|
33
|
+
const n = ownDataField(column, 'length');
|
|
34
|
+
if (typeof n !== 'number' || !Number.isInteger(n) || n < 0)
|
|
35
|
+
return undefined;
|
|
36
|
+
const keys = new Set();
|
|
37
|
+
for (let i = 0; i < n; i += 1) {
|
|
38
|
+
const key = ownDataField(column, String(i));
|
|
39
|
+
if (typeof key !== 'string')
|
|
40
|
+
return undefined;
|
|
41
|
+
keys.add(key);
|
|
42
|
+
}
|
|
43
|
+
out.set(type, keys);
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function hooksEntryKeyReaderOf(settingsContract, serverVersion) {
|
|
52
|
+
if (settingsContract.kind === 'value') {
|
|
53
|
+
const fields = hookEntryFieldsOf(settingsContract.value);
|
|
54
|
+
if (fields !== undefined) {
|
|
55
|
+
return Object.freeze({ fields: 'reported', reads: (entryType, key) => key === 'type' || (fields.get(entryType)?.has(key) ?? false) });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const fields = settingsContract.kind === 'unobserved' ? null : settingsContract.kind === 'not_reported' ? 'not_reported' : 'unreadable';
|
|
59
|
+
const notRead = hooksReaderNotReadKeys(serverVersion);
|
|
60
|
+
return Object.freeze({ fields, reads: (_entryType, key, carriedByCopy) => carriedByCopy && !notRead.includes(key) });
|
|
61
|
+
}
|