@sema-agent/client-core 0.93.1 → 0.94.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 +213 -0
- package/README.md +30 -19
- package/dist/adapt/arms.js +8 -5
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -1
- package/dist/agentsWireCaps.d.ts +15 -0
- package/dist/agentsWireCaps.js +111 -1
- package/dist/approvalReachWire.d.ts +18 -0
- package/dist/approvalReachWire.js +58 -0
- package/dist/approvalsStreamLiveCapability.js +16 -11
- package/dist/callerCwdCapability.d.ts +16 -0
- package/dist/callerCwdCapability.js +47 -0
- package/dist/controlRouter.js +3 -10
- package/dist/coreValuePorts.d.ts +64 -1
- package/dist/coreValuePorts.js +30 -0
- package/dist/detachWire.d.ts +1 -4
- package/dist/detachWire.js +1 -1
- package/dist/deviceExecutorManagementCapability.js +39 -34
- package/dist/deviceFlowPolling.d.ts +5 -0
- package/dist/deviceFlowPolling.js +28 -0
- package/dist/displayUntrusted.js +652 -21
- package/dist/engineErrorCodes.d.ts +5 -1
- package/dist/engineErrorCodes.js +9 -12
- package/dist/engineNoticeCodes.d.ts +22 -2
- package/dist/engineNoticeCodes.js +73 -6
- package/dist/engineRefusedToolName.d.ts +1 -0
- package/dist/engineRefusedToolName.js +8 -0
- package/dist/executionLaneCapability.js +14 -9
- package/dist/fileHistoryCaptureCapability.js +14 -9
- package/dist/fileHistoryLegNotice.d.ts +11 -0
- package/dist/fileHistoryLegNotice.js +50 -13
- package/dist/fleet/fleetLedger.js +5 -0
- package/dist/gateOutcome.d.ts +2 -1
- package/dist/gateOutcome.js +3 -0
- package/dist/gateVocabulary.js +1 -1
- package/dist/generated/engineAskFaceTables.d.ts +3 -0
- package/dist/generated/engineAskFaceTables.js +12 -0
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +13 -0
- package/dist/generated/engineNoticeTables.d.ts +5 -0
- package/dist/generated/engineNoticeTables.js +7 -0
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaTables.d.ts +3 -0
- package/dist/generated/settingsSchemaTables.js +3 -0
- package/dist/headlessPermissionModeWire.d.ts +2 -2
- package/dist/headlessPermissionModeWire.js +11 -21
- package/dist/hitl/approvalHolds.d.ts +36 -0
- package/dist/hitl/approvalHolds.js +89 -0
- package/dist/hitl/approvalOutcomeNote.js +2 -1
- package/dist/hitl/approvalResolution.js +9 -1
- package/dist/hitl/approvalsFeed.js +5 -0
- package/dist/hitl/askGateWire.js +3 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
- package/dist/hitl/automaticAnswerVerdict.js +69 -21
- package/dist/hitl/decisionRefusal.d.ts +19 -0
- package/dist/hitl/decisionRefusal.js +63 -0
- package/dist/hitl/frameRouter.d.ts +10 -0
- package/dist/hitl/frameRouter.js +59 -3
- package/dist/hitl/gateLedger.d.ts +3 -0
- package/dist/hitl/gateLedger.js +17 -0
- package/dist/hitl/hitlBridge.d.ts +2 -2
- package/dist/hitl/hitlBridge.js +8 -10
- package/dist/hitl/hitlHostSurface.d.ts +3 -0
- package/dist/hitl/hitlHostSurface.js +14 -4
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +9 -0
- package/dist/hitl/noAllowCause.js +26 -0
- package/dist/hitl/parkResolver.js +6 -3
- package/dist/hitl/parkRowBirthWait.js +2 -1
- package/dist/hitl/persistedRulesWire.d.ts +6 -1
- package/dist/hitl/persistedRulesWire.js +12 -4
- package/dist/hitl/planReviewWire.d.ts +0 -1
- package/dist/hitl/planReviewWire.js +30 -9
- package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
- package/dist/hitl/sessionPolicyDeliverable.js +3 -8
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +27 -2
- package/dist/hitl/toolApprovalWire.js +258 -23
- package/dist/humanTurnRead.d.ts +15 -1
- package/dist/humanTurnRead.js +28 -2
- package/dist/index.d.ts +18 -6
- package/dist/index.js +14 -5
- package/dist/limitsWire.d.ts +0 -1
- package/dist/limitsWire.js +2 -10
- package/dist/liveModelCatalog.d.ts +14 -0
- package/dist/liveModelCatalog.js +61 -0
- package/dist/mcpProbeCapability.js +14 -9
- package/dist/mcpReconnect.js +13 -8
- package/dist/memoryComplianceCapability.js +15 -10
- package/dist/memoryOriginCapability.js +15 -10
- package/dist/modelIdentityResolvability.d.ts +4 -2
- package/dist/modelIdentityResolvability.js +31 -4
- package/dist/outputStyleSeatCapability.d.ts +16 -0
- package/dist/outputStyleSeatCapability.js +47 -0
- package/dist/ownKey.d.ts +1 -0
- package/dist/ownKey.js +10 -0
- package/dist/peerLaneCapability.js +16 -11
- package/dist/permissionRuleIssue.js +1 -1
- package/dist/permissionRulesWriteCapability.js +16 -11
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +38 -16
- package/dist/permissionsDeclaration.d.ts +10 -1
- package/dist/permissionsDeclaration.js +97 -15
- package/dist/protocolSegment.d.ts +1 -0
- package/dist/protocolSegment.js +13 -1
- package/dist/request/taskRequest.d.ts +11 -3
- package/dist/request/taskRequest.js +13 -1
- package/dist/resultFrameKeys.d.ts +4 -0
- package/dist/resultFrameKeys.js +13 -0
- package/dist/resumeRefusalCopy.js +6 -16
- package/dist/retryStatus.js +6 -4
- package/dist/rewindArchiveCapability.js +13 -8
- package/dist/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
- package/dist/runCancelContext.js +2 -1
- package/dist/sealedKeyCapability.js +19 -14
- package/dist/seatContract.d.ts +33 -5
- package/dist/seatContract.js +143 -2
- package/dist/sessionPolicyCapability.js +15 -10
- package/dist/sessionReadRedactionCapability.d.ts +16 -0
- package/dist/sessionReadRedactionCapability.js +47 -0
- package/dist/sessionSyncFileHistoryCapability.js +14 -9
- package/dist/skillToolListsCapability.js +14 -9
- package/dist/sqlEngineCapability.js +18 -13
- package/dist/steerPriorityCapability.js +21 -16
- package/dist/subagent/agentStateDetail.d.ts +1 -0
- package/dist/subagent/agentStateDetail.js +41 -0
- package/dist/subagent/engineCompactWire.d.ts +15 -0
- package/dist/subagent/engineCompactWire.js +75 -13
- package/dist/supportFloor.js +1 -1
- package/dist/taskRequestWords.d.ts +2 -4
- package/dist/taskRequestWords.js +3 -2
- package/dist/types/engineState.d.ts +1 -1
- package/dist/userAttachmentEnvelope.d.ts +22 -1
- package/dist/userAttachmentEnvelope.js +90 -2
- package/dist/userInvokedSkillsCapability.js +14 -9
- package/dist/webSearchBackendCapability.js +21 -16
- package/dist/wireErrorTriage.d.ts +11 -0
- package/dist/wireErrorTriage.js +35 -0
- package/dist/wireFailureShape.d.ts +6 -0
- package/dist/wireFailureShape.js +30 -3
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +22 -8
- package/dist/wiringInstructionsAttribution.d.ts +10 -0
- package/dist/wiringInstructionsAttribution.js +67 -0
- package/dist/workflowClient.js +22 -1
- package/dist/workflowsJournalCapability.js +14 -9
- package/dist/writeProtectionCapability.js +28 -23
- package/docs/INTEGRATION-CLIENTS.md +719 -45
- package/package.json +5 -5
- package/dist/askSurvivesStandingAnswer.d.ts +0 -13
- package/dist/askSurvivesStandingAnswer.js +0 -53
- package/dist/hitl/askSurvivesPosture.d.ts +0 -20
- package/dist/hitl/askSurvivesPosture.js +0 -48
- /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
|
@@ -6,7 +6,7 @@ import { type DenyAttributionRefusalDetail } from '../wireRefusalCopy.js';
|
|
|
6
6
|
import { type ApprovalDecidedByReading } from '../approvalDecidedByCapability.js';
|
|
7
7
|
import { type DecideReceiptView } from '../decideReceipt.js';
|
|
8
8
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS } from '@sema-agent/sdk';
|
|
9
|
-
import type { ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
|
|
9
|
+
import type { ApprovalDecidedBy, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
|
|
10
10
|
export declare function isFsApprovalGate(gate: {
|
|
11
11
|
kind?: unknown;
|
|
12
12
|
toolName?: unknown;
|
|
@@ -157,6 +157,15 @@ export interface ApprovalCardRequest {
|
|
|
157
157
|
origin?: string;
|
|
158
158
|
askClass?: string;
|
|
159
159
|
classes?: readonly string[];
|
|
160
|
+
boundGrants?: BoundSkillGrantsWire;
|
|
161
|
+
classifierNoRuling?: string;
|
|
162
|
+
priorCardsForCall?: readonly ApprovalPriorCard[];
|
|
163
|
+
}
|
|
164
|
+
export interface ApprovalPriorCard {
|
|
165
|
+
readonly approvalId?: string;
|
|
166
|
+
readonly origin?: string;
|
|
167
|
+
readonly mandate?: ApprovalMandateWord;
|
|
168
|
+
readonly outcome?: 'allowed' | 'denied';
|
|
160
169
|
}
|
|
161
170
|
export type ApprovalCardPort = (req: ApprovalCardRequest) => Promise<ApprovalCardDecision>;
|
|
162
171
|
export declare function installApprovalCardPort(port: ApprovalCardPort | null): () => void;
|
|
@@ -244,7 +253,7 @@ export interface RespondToolApprovalOpts {
|
|
|
244
253
|
persistRuleBatchOfferIndex?: number;
|
|
245
254
|
note?: string;
|
|
246
255
|
settledBy?: 'policy';
|
|
247
|
-
decidedBy?: 'policy'
|
|
256
|
+
decidedBy?: Extract<ApprovalDecidedBy, 'policy'>;
|
|
248
257
|
}
|
|
249
258
|
export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<ToolApprovalRespondAck | void>;
|
|
250
259
|
export type ToolApprovalRespondAckView = ToolApprovalRespondAck;
|
|
@@ -254,7 +263,15 @@ export interface ToolApprovalRespondParkingView {
|
|
|
254
263
|
readonly approvalId: string;
|
|
255
264
|
readonly retryAfterMs?: number;
|
|
256
265
|
readonly decidePath?: string;
|
|
266
|
+
readonly message?: string;
|
|
257
267
|
}
|
|
268
|
+
export type ToolApprovalParkingBodyReading = {
|
|
269
|
+
readonly kind: 'parking';
|
|
270
|
+
readonly view: ToolApprovalRespondParkingView;
|
|
271
|
+
} | {
|
|
272
|
+
readonly kind: 'claimed_unreadable';
|
|
273
|
+
};
|
|
274
|
+
export declare function readToolApprovalRespondParking(v: unknown): ToolApprovalParkingBodyReading | undefined;
|
|
258
275
|
export declare function decisionAttributionKeyOf(reading: ApprovalDecidedByReading | undefined, denySettledBy: ApprovalDenySettledBy | undefined): {
|
|
259
276
|
decidedBy: 'policy';
|
|
260
277
|
} | {
|
|
@@ -266,6 +283,8 @@ export interface ToolApprovalFrameOutcome {
|
|
|
266
283
|
respondRefusal?: ToolApprovalRespondRefusal;
|
|
267
284
|
editRefused?: true;
|
|
268
285
|
retracted?: true;
|
|
286
|
+
aborted?: true;
|
|
287
|
+
joinedInFlight?: true;
|
|
269
288
|
denySettledBy?: ApprovalDenySettledBy;
|
|
270
289
|
denyReason?: string;
|
|
271
290
|
denyAttributionRefusal?: DenyAttributionRefusalDetail;
|
|
@@ -287,6 +306,12 @@ export type ToolApprovalRespondRefusal = (ToolApprovalRespondRefusalFields & {
|
|
|
287
306
|
});
|
|
288
307
|
export declare function readToolApprovalRespondRefusal(err: unknown): ToolApprovalRespondRefusal | undefined;
|
|
289
308
|
export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
|
|
309
|
+
export declare function askProbeReasonDetail(card: Pick<ApprovalCardRequest, 'probeReason' | 'probeCause'> | null | undefined): string | undefined;
|
|
310
|
+
export declare function readApprovalBoundGrants(v: unknown): BoundSkillGrantsWire | undefined;
|
|
311
|
+
export declare function readApprovalClassifierNoRuling(v: unknown): string | undefined;
|
|
312
|
+
export declare function classifierNoRulingDetail(word: string | undefined): string;
|
|
313
|
+
export declare function approvalBoundGrantsDetail(grants: BoundSkillGrantsWire | null | undefined): string | undefined;
|
|
314
|
+
export declare function approvalPriorCardsDetail(card: Pick<ApprovalCardRequest, 'priorCardsForCall' | 'origin'> | null | undefined): string | undefined;
|
|
290
315
|
export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
|
|
291
316
|
export declare function readRuleOffers(v: unknown): RuleOffer[] | undefined;
|
|
292
317
|
export declare function readRuleOfferSupply(offers: unknown): RuleOffer[] | undefined;
|
|
@@ -6,12 +6,16 @@ import { readAskClassPair } from './askClassPair.js';
|
|
|
6
6
|
import { legacyShadowedRuleTextOf, readAllowRuleShadowFromWire } from './allowRuleShadow.js';
|
|
7
7
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
8
8
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
9
|
-
import { observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
9
|
+
import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
10
10
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
11
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
12
|
+
import { approvalDecisionHolds, holdLiveCard, joinLiveCard, liveCardHoldOf } from './approvalHolds.js';
|
|
13
|
+
import { approvalResolutionOf } from './approvalResolution.js';
|
|
11
14
|
import { isApprovalMandateWord } from '../gateVocabulary.js';
|
|
12
15
|
import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
|
|
13
16
|
import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
|
|
14
17
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
18
|
+
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
15
19
|
import { refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
16
20
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
17
21
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, PERSISTED_RULE_MANDATES, } from '@sema-agent/sdk';
|
|
@@ -110,6 +114,7 @@ export function approvalCardPortFor(sessionKey) {
|
|
|
110
114
|
export function _resetApprovalCardPortForTest() {
|
|
111
115
|
cardPortByKey.clear();
|
|
112
116
|
cardPortMissesByKey.clear();
|
|
117
|
+
callCardLedger.clear();
|
|
113
118
|
}
|
|
114
119
|
export function surfaceApprovalCard(req) {
|
|
115
120
|
const cardPort = approvalCardPortFor(DEFAULT_SESSION_KEY);
|
|
@@ -170,17 +175,17 @@ function isParkRowInputSizeMarker(v) {
|
|
|
170
175
|
const o = v;
|
|
171
176
|
return o.truncated === true && typeof o.bytes === 'number' && Number.isFinite(o.bytes) && o.bytes >= 0;
|
|
172
177
|
}
|
|
173
|
-
const durableDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
|
|
174
178
|
function durableHoldKey(row, callKey) {
|
|
175
|
-
|
|
179
|
+
const createdAt = typeof row.createdAt === 'number' && Number.isFinite(row.createdAt) ? row.createdAt : null;
|
|
180
|
+
return JSON.stringify([typeof row.sessionId === 'string' ? row.sessionId : null, typeof row.taskId === 'string' ? row.taskId : null, callKey, createdAt]);
|
|
176
181
|
}
|
|
177
182
|
function openDurableRead() {
|
|
178
|
-
const mark = ++
|
|
179
|
-
|
|
183
|
+
const mark = ++approvalDecisionHolds.clock;
|
|
184
|
+
approvalDecisionHolds.openReads.add(mark);
|
|
180
185
|
return mark;
|
|
181
186
|
}
|
|
182
187
|
function closeDurableRead(mark) {
|
|
183
|
-
const h =
|
|
188
|
+
const h = approvalDecisionHolds;
|
|
184
189
|
h.openReads.delete(mark);
|
|
185
190
|
let oldest = Infinity;
|
|
186
191
|
for (const m of h.openReads)
|
|
@@ -191,14 +196,14 @@ function closeDurableRead(mark) {
|
|
|
191
196
|
h.settled.delete(key);
|
|
192
197
|
}
|
|
193
198
|
function heldDurableDecision(holdKey, readMark) {
|
|
194
|
-
const live =
|
|
199
|
+
const live = approvalDecisionHolds.inFlight.get(holdKey);
|
|
195
200
|
if (live !== undefined)
|
|
196
|
-
return live;
|
|
197
|
-
const recent =
|
|
201
|
+
return live.lane === 'durable' ? live : undefined;
|
|
202
|
+
const recent = approvalDecisionHolds.settled.get(holdKey);
|
|
198
203
|
return recent !== undefined && recent.at > readMark ? recent.hold : undefined;
|
|
199
204
|
}
|
|
200
205
|
function holdDurableDecision(holdKey, callerSignal, decide) {
|
|
201
|
-
const h =
|
|
206
|
+
const h = approvalDecisionHolds;
|
|
202
207
|
const interruption = new AbortController();
|
|
203
208
|
let settled = false;
|
|
204
209
|
const interrupt = () => {
|
|
@@ -215,7 +220,7 @@ function holdDurableDecision(holdKey, callerSignal, decide) {
|
|
|
215
220
|
resolveOutcome = resolve;
|
|
216
221
|
rejectOutcome = reject;
|
|
217
222
|
});
|
|
218
|
-
const hold = { outcome, presented: false, interrupt, cardSignal: interruption.signal };
|
|
223
|
+
const hold = { lane: 'durable', outcome, presented: false, interrupt, cardSignal: interruption.signal };
|
|
219
224
|
h.inFlight.set(holdKey, hold);
|
|
220
225
|
const release = () => {
|
|
221
226
|
if (h.inFlight.get(holdKey) === hold)
|
|
@@ -278,9 +283,14 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
278
283
|
return joinDurableDecision(held, deps, signal);
|
|
279
284
|
const callKey = approvalCallKey(found.gatedCallId, taskId);
|
|
280
285
|
const fetched = found;
|
|
281
|
-
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), signal, (hold) =>
|
|
286
|
+
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), signal, async (hold) => {
|
|
287
|
+
const slot = {};
|
|
288
|
+
const out = await presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, fetched, decidedByReading, callKey, hold, slot);
|
|
289
|
+
noteCallOutcome(slot, out);
|
|
290
|
+
return out;
|
|
291
|
+
});
|
|
282
292
|
}
|
|
283
|
-
async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, found, decidedByReading, callKey, hold) {
|
|
293
|
+
async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, found, decidedByReading, callKey, hold, ledgerSlot) {
|
|
284
294
|
const { pending, gatedCallId } = found;
|
|
285
295
|
const toolName = typeof pending.toolName === 'string' ? pending.toolName : '';
|
|
286
296
|
const streamArgs = gatedCallId !== undefined ? argsByCall.get(gatedCallId) : undefined;
|
|
@@ -304,7 +314,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
304
314
|
const durableRuleOffersAbsence = pending.ruleOffersAbsence;
|
|
305
315
|
hold.presented = true;
|
|
306
316
|
deps.onPresented?.();
|
|
307
|
-
const card = await
|
|
317
|
+
const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, {
|
|
308
318
|
toolName,
|
|
309
319
|
args,
|
|
310
320
|
callKey,
|
|
@@ -352,7 +362,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
352
362
|
return { kind: 'retracted', gatedCallId };
|
|
353
363
|
case 'aborted':
|
|
354
364
|
{
|
|
355
|
-
const cancelDeny = bridge.decideTool({ decision: 'deny', reason:
|
|
365
|
+
const cancelDeny = bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId, undefined, pending);
|
|
356
366
|
hold.trailing = cancelDeny;
|
|
357
367
|
observeCancelByDeny(cancelDeny, taskId);
|
|
358
368
|
}
|
|
@@ -393,11 +403,13 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
393
403
|
const wireCode = readWireErrorCode(e);
|
|
394
404
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
395
405
|
const safetyCode = e instanceof HitlSafetyError ? e.code : undefined;
|
|
406
|
+
const failureTexts = wireFailureTextsOf(e);
|
|
407
|
+
hostLog('debug', `liveToolApprovalWire: decide(approve) failed: ${failureTexts.log}`);
|
|
396
408
|
return {
|
|
397
409
|
kind: 'failed',
|
|
398
410
|
stage: 'decide',
|
|
399
411
|
gatedCallId,
|
|
400
|
-
reason: `decide(approve) failed: ${
|
|
412
|
+
reason: `decide(approve) failed: ${failureTexts.reason}${decideFailureNote(e, 'approve')}`,
|
|
401
413
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
402
414
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
403
415
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
@@ -478,11 +490,13 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
478
490
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
479
491
|
const safetyCode = e instanceof HitlSafetyError ? e.code : undefined;
|
|
480
492
|
const attributionRefusal = denyAttributionRefusalFromError(e, lastSendCarriedAttribution);
|
|
493
|
+
const failureTexts = wireFailureTextsOf(e);
|
|
494
|
+
hostLog('debug', `liveToolApprovalWire: decide(deny) failed: ${failureTexts.log}`);
|
|
481
495
|
return {
|
|
482
496
|
kind: 'failed',
|
|
483
497
|
stage: 'decide',
|
|
484
498
|
gatedCallId,
|
|
485
|
-
reason: `decide(deny) failed: ${
|
|
499
|
+
reason: `decide(deny) failed: ${failureTexts.reason}${decideFailureNote(e, 'deny')}`,
|
|
486
500
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
487
501
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
488
502
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
@@ -656,7 +670,7 @@ export function readToolApprovalRespondAck(v) {
|
|
|
656
670
|
}
|
|
657
671
|
return out;
|
|
658
672
|
}
|
|
659
|
-
function readToolApprovalRespondParking(v) {
|
|
673
|
+
export function readToolApprovalRespondParking(v) {
|
|
660
674
|
if (typeof v !== 'object' || v === null)
|
|
661
675
|
return undefined;
|
|
662
676
|
const read = (fn) => {
|
|
@@ -675,7 +689,16 @@ function readToolApprovalRespondParking(v) {
|
|
|
675
689
|
const hint = read(() => readOwnDataValue(v, 'retryAfterMs'));
|
|
676
690
|
const retryAfterMs = typeof hint === 'number' && Number.isFinite(hint) && hint >= 0 ? hint : undefined;
|
|
677
691
|
const decidePath = read(() => readOwnDataNonEmptyString(v, 'decidePath'));
|
|
678
|
-
|
|
692
|
+
const message = read(() => readOwnDataNonEmptyString(v, 'message'));
|
|
693
|
+
return {
|
|
694
|
+
kind: 'parking',
|
|
695
|
+
view: {
|
|
696
|
+
approvalId,
|
|
697
|
+
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
698
|
+
...(decidePath !== undefined ? { decidePath } : {}),
|
|
699
|
+
...(message !== undefined ? { message } : {}),
|
|
700
|
+
},
|
|
701
|
+
};
|
|
679
702
|
}
|
|
680
703
|
function isNonEmptyStringArray(v) {
|
|
681
704
|
return Array.isArray(v) && v.length > 0 && v.every(x => typeof x === 'string' && x !== '');
|
|
@@ -830,13 +853,27 @@ function readProbeReason(v) {
|
|
|
830
853
|
try {
|
|
831
854
|
if (typeof v !== 'object' || v === null || !Object.hasOwn(v, 'probeReason'))
|
|
832
855
|
return undefined;
|
|
833
|
-
|
|
834
|
-
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
856
|
+
return usableProbeReason(v.probeReason);
|
|
835
857
|
}
|
|
836
858
|
catch {
|
|
837
859
|
return undefined;
|
|
838
860
|
}
|
|
839
861
|
}
|
|
862
|
+
function usableProbeReason(raw) {
|
|
863
|
+
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
864
|
+
}
|
|
865
|
+
const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
|
|
866
|
+
export function askProbeReasonDetail(card) {
|
|
867
|
+
const reason = usableProbeReason(ownDataValue(card, 'probeReason'));
|
|
868
|
+
if (reason !== undefined)
|
|
869
|
+
return displayUntrusted(reason);
|
|
870
|
+
const cause = ownDataValue(card, 'probeCause');
|
|
871
|
+
if (!isWireRecordCarrier(cause))
|
|
872
|
+
return undefined;
|
|
873
|
+
const code = ownDataValue(cause, 'code');
|
|
874
|
+
const head = 'An automatic check could not clear this call, so it is asking you; the engine did not say the specific reason';
|
|
875
|
+
return typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code) ? `${head} (check code: ${code}).` : `${head}.`;
|
|
876
|
+
}
|
|
840
877
|
function readRememberRefused(v) {
|
|
841
878
|
try {
|
|
842
879
|
return typeof v === 'object' && v !== null && Object.hasOwn(v, 'rememberRefused') && v.rememberRefused === true;
|
|
@@ -845,6 +882,167 @@ function readRememberRefused(v) {
|
|
|
845
882
|
return false;
|
|
846
883
|
}
|
|
847
884
|
}
|
|
885
|
+
function ownDataValue(v, key) {
|
|
886
|
+
if (typeof v !== 'object' || v === null)
|
|
887
|
+
return undefined;
|
|
888
|
+
try {
|
|
889
|
+
const d = Object.getOwnPropertyDescriptor(v, key);
|
|
890
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
891
|
+
}
|
|
892
|
+
catch {
|
|
893
|
+
return undefined;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function ownStringList(v) {
|
|
897
|
+
if (!Array.isArray(v))
|
|
898
|
+
return undefined;
|
|
899
|
+
try {
|
|
900
|
+
const length = v.length;
|
|
901
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
|
|
902
|
+
return undefined;
|
|
903
|
+
const out = [];
|
|
904
|
+
for (let i = 0; i < length; i++) {
|
|
905
|
+
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
906
|
+
if (d === undefined || !('value' in d) || typeof d.value !== 'string' || d.value === '')
|
|
907
|
+
return undefined;
|
|
908
|
+
out.push(d.value);
|
|
909
|
+
}
|
|
910
|
+
return v.length === length ? Object.freeze(out) : undefined;
|
|
911
|
+
}
|
|
912
|
+
catch {
|
|
913
|
+
return undefined;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
export function readApprovalBoundGrants(v) {
|
|
917
|
+
const g = ownDataValue(v, 'boundGrants');
|
|
918
|
+
if (typeof g !== 'object' || g === null || Array.isArray(g))
|
|
919
|
+
return undefined;
|
|
920
|
+
const skill = ownDataValue(g, 'skill');
|
|
921
|
+
if (!(skill === null || (typeof skill === 'string' && skill !== '')))
|
|
922
|
+
return undefined;
|
|
923
|
+
const allowedTools = ownStringList(ownDataValue(g, 'allowedTools'));
|
|
924
|
+
const disallowedTools = ownStringList(ownDataValue(g, 'disallowedTools'));
|
|
925
|
+
if (allowedTools === undefined || disallowedTools === undefined)
|
|
926
|
+
return undefined;
|
|
927
|
+
return Object.freeze({ skill, allowedTools, disallowedTools });
|
|
928
|
+
}
|
|
929
|
+
const CAUSE_WORD = /^[a-z][a-z0-9_]{0,63}$/;
|
|
930
|
+
export function readApprovalClassifierNoRuling(v) {
|
|
931
|
+
const w = ownDataValue(v, 'classifierNoRuling');
|
|
932
|
+
return typeof w === 'string' && CAUSE_WORD.test(w) ? w : undefined;
|
|
933
|
+
}
|
|
934
|
+
const CLASSIFIER_NO_RULING_REASONS = Object.freeze({
|
|
935
|
+
error: 'could not run for this call (it failed)',
|
|
936
|
+
timeout: 'could not run for this call (it timed out)',
|
|
937
|
+
parse_error: 'answered for this call but gave no verdict it could use',
|
|
938
|
+
});
|
|
939
|
+
const _noRulingPin = [true, true];
|
|
940
|
+
void _noRulingPin;
|
|
941
|
+
export function classifierNoRulingDetail(word) {
|
|
942
|
+
if (typeof word === 'string' && Object.hasOwn(CLASSIFIER_NO_RULING_REASONS, word)) {
|
|
943
|
+
return `The auto-mode classifier ${CLASSIFIER_NO_RULING_REASONS[word]}, so it is asking you instead.`;
|
|
944
|
+
}
|
|
945
|
+
if (typeof word === 'string' && CAUSE_WORD.test(word))
|
|
946
|
+
return `The auto-mode classifier did not rule on this call (reason: ${word}), so it is asking you instead.`;
|
|
947
|
+
return 'The auto-mode classifier did not rule on this call, so it is asking you instead.';
|
|
948
|
+
}
|
|
949
|
+
const entries = (n) => (n === 1 ? '1 tool entry' : `${String(n)} tool entries`);
|
|
950
|
+
export function approvalBoundGrantsDetail(grants) {
|
|
951
|
+
const g = readApprovalBoundGrants({ boundGrants: grants });
|
|
952
|
+
if (g === undefined)
|
|
953
|
+
return undefined;
|
|
954
|
+
if (g.skill === null)
|
|
955
|
+
return 'This call names no loaded skill, so approving it grants nothing beyond this call.';
|
|
956
|
+
const a = g.allowedTools.length;
|
|
957
|
+
const d = g.disallowedTools.length;
|
|
958
|
+
if (a === 0 && d === 0)
|
|
959
|
+
return 'Approving this activates the skill shown on the card; it lists no tools to run without asking and none to refuse.';
|
|
960
|
+
const allow = `${entries(a)} it lists ${a === 1 ? 'runs' : 'run'} without asking once it is active`;
|
|
961
|
+
const deny = `${entries(d)} ${d === 1 ? 'is' : 'are'} refused for the rest of this run`;
|
|
962
|
+
return `Approving this activates the skill shown on the card: ${allow}, and ${deny}.`;
|
|
963
|
+
}
|
|
964
|
+
const CALL_LEDGER_MAX_CALLS = 256;
|
|
965
|
+
const CALL_LEDGER_MAX_ASKS_PER_CALL = 8;
|
|
966
|
+
const callCardLedger = new Map();
|
|
967
|
+
function askSignatureOf(req) {
|
|
968
|
+
return JSON.stringify([req.classes !== undefined ? [...req.classes] : null, req.origin ?? null, req.mandate ?? null]);
|
|
969
|
+
}
|
|
970
|
+
function priorCardView(a) {
|
|
971
|
+
return Object.freeze({
|
|
972
|
+
...(a.approvalId !== undefined ? { approvalId: a.approvalId } : {}),
|
|
973
|
+
...(a.origin !== undefined ? { origin: a.origin } : {}),
|
|
974
|
+
...(a.mandate !== undefined ? { mandate: a.mandate } : {}),
|
|
975
|
+
...(a.outcome !== undefined ? { outcome: a.outcome } : {}),
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
function noteCardOnCall(callId, approvalId, req) {
|
|
979
|
+
const sig = askSignatureOf(req);
|
|
980
|
+
let asks = callCardLedger.get(callId);
|
|
981
|
+
if (asks === undefined) {
|
|
982
|
+
asks = [];
|
|
983
|
+
callCardLedger.set(callId, asks);
|
|
984
|
+
while (callCardLedger.size > CALL_LEDGER_MAX_CALLS) {
|
|
985
|
+
const oldest = callCardLedger.keys().next().value;
|
|
986
|
+
if (oldest === undefined)
|
|
987
|
+
break;
|
|
988
|
+
callCardLedger.delete(oldest);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
let at = asks.findIndex((a) => a.sig === sig);
|
|
992
|
+
if (at < 0) {
|
|
993
|
+
asks.push({ sig, ...(approvalId !== undefined ? { approvalId } : {}), ...(req.origin !== undefined ? { origin: req.origin } : {}), ...(req.mandate !== undefined ? { mandate: req.mandate } : {}) });
|
|
994
|
+
while (asks.length > CALL_LEDGER_MAX_ASKS_PER_CALL)
|
|
995
|
+
asks.shift();
|
|
996
|
+
at = asks.length - 1;
|
|
997
|
+
}
|
|
998
|
+
else if (asks[at].approvalId === undefined && approvalId !== undefined) {
|
|
999
|
+
asks[at].approvalId = approvalId;
|
|
1000
|
+
}
|
|
1001
|
+
const entry = asks[at];
|
|
1002
|
+
const prior = asks.slice(0, at);
|
|
1003
|
+
return { entry, ...(prior.length > 0 ? { prior: Object.freeze(prior.map(priorCardView)) } : {}) };
|
|
1004
|
+
}
|
|
1005
|
+
async function surfaceCallTrackedCard(callId, approvalId, slot, req) {
|
|
1006
|
+
if (callId === undefined || callId === '')
|
|
1007
|
+
return surfaceApprovalCard(req);
|
|
1008
|
+
const { entry, prior } = noteCardOnCall(callId, approvalId, req);
|
|
1009
|
+
slot.entry = entry;
|
|
1010
|
+
return surfaceApprovalCard(prior !== undefined ? { ...req, priorCardsForCall: prior } : req);
|
|
1011
|
+
}
|
|
1012
|
+
function noteCallOutcome(slot, outcome) {
|
|
1013
|
+
const entry = slot.entry;
|
|
1014
|
+
if (entry === undefined)
|
|
1015
|
+
return;
|
|
1016
|
+
const r = approvalResolutionOf(outcome);
|
|
1017
|
+
if (r.kind === 'decided')
|
|
1018
|
+
entry.outcome = r.decision === 'deny' ? 'denied' : 'allowed';
|
|
1019
|
+
}
|
|
1020
|
+
export function approvalPriorCardsDetail(card) {
|
|
1021
|
+
const prior = ownDataValue(card, 'priorCardsForCall');
|
|
1022
|
+
let isList = false;
|
|
1023
|
+
try {
|
|
1024
|
+
isList = Array.isArray(prior);
|
|
1025
|
+
}
|
|
1026
|
+
catch {
|
|
1027
|
+
return undefined;
|
|
1028
|
+
}
|
|
1029
|
+
if (!isList)
|
|
1030
|
+
return undefined;
|
|
1031
|
+
const length = ownDataValue(prior, 'length');
|
|
1032
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length <= 0 || length > CALL_LEDGER_MAX_ASKS_PER_CALL)
|
|
1033
|
+
return undefined;
|
|
1034
|
+
const items = [];
|
|
1035
|
+
for (let i = 0; i < length; i++)
|
|
1036
|
+
items.push(ownDataValue(prior, String(i)));
|
|
1037
|
+
const outcome = ownDataValue(items[length - 1], 'outcome');
|
|
1038
|
+
const earlier = outcome === 'allowed' ? 'you already approved an earlier one' : outcome === 'denied' ? 'an earlier one was denied' : 'an earlier one was shown first';
|
|
1039
|
+
const fromRule = items.some((p) => ownDataValue(p, 'origin') === 'ask_rule');
|
|
1040
|
+
const thisFromRule = ownDataValue(card, 'origin') === 'ask_rule';
|
|
1041
|
+
if (fromRule && !thisFromRule) {
|
|
1042
|
+
return `This is a second approval for the same call: ${earlier}, which your ask rule asked for. This one is a separate check, not from your ask rule, and needs its own answer.`;
|
|
1043
|
+
}
|
|
1044
|
+
return `This is a second approval for the same call: ${earlier}. This one is a separate check and needs its own answer.`;
|
|
1045
|
+
}
|
|
848
1046
|
function isNonNegativeFinite(v) {
|
|
849
1047
|
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
850
1048
|
}
|
|
@@ -1012,6 +1210,18 @@ function subagentBadgeFor(frame) {
|
|
|
1012
1210
|
const MAX_RESPOND_NOTE_CHARS = 2048;
|
|
1013
1211
|
export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane) {
|
|
1014
1212
|
const approvalId = frame.approvalId;
|
|
1213
|
+
const key = liveFrameCallKey(approvalId);
|
|
1214
|
+
const held = liveCardHoldOf(key);
|
|
1215
|
+
if (held !== undefined)
|
|
1216
|
+
return joinLiveCard(held, signal);
|
|
1217
|
+
return holdLiveCard(key, signal, async (hold) => {
|
|
1218
|
+
const slot = {};
|
|
1219
|
+
const out = await presentToolApprovalFrameAndRespond(frame, approvalId, respond, streamArgs, signal, lane, hold, slot);
|
|
1220
|
+
noteCallOutcome(slot, out);
|
|
1221
|
+
return out;
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot) {
|
|
1015
1225
|
const frameToolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
|
|
1016
1226
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
1017
1227
|
const toolName = typeof frame.toolName === 'string' ? frame.toolName : 'Write';
|
|
@@ -1041,14 +1251,14 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1041
1251
|
const ruleOffers = readRuleOffers(frame.ruleOffers);
|
|
1042
1252
|
const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
|
|
1043
1253
|
const frameShadow = readAllowRuleShadowFromWire(frame, 'frame');
|
|
1044
|
-
const card = await
|
|
1254
|
+
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
|
|
1045
1255
|
toolName,
|
|
1046
1256
|
args: args,
|
|
1047
1257
|
callKey: liveFrameCallKey(approvalId),
|
|
1048
1258
|
...(frameToolCallId !== undefined
|
|
1049
1259
|
? { toolCallId: frameToolCallId }
|
|
1050
1260
|
: {}),
|
|
1051
|
-
|
|
1261
|
+
signal: hold.cardSignal,
|
|
1052
1262
|
...(isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {}),
|
|
1053
1263
|
...(wireNote !== undefined ? { wireNote } : {}),
|
|
1054
1264
|
...(argsNotRealInput ? { argsUnavailable: true } : {}),
|
|
@@ -1084,7 +1294,16 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1084
1294
|
...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
|
|
1085
1295
|
...((o) => (o !== undefined ? { origin: o } : {}))(readOwnNonEmptyString(frame, 'origin')),
|
|
1086
1296
|
...(readAskClassPair(frame) ?? {}),
|
|
1297
|
+
...((g) => (g !== undefined ? { boundGrants: g } : {}))(readApprovalBoundGrants(frame)),
|
|
1298
|
+
...((w) => (w !== undefined ? { classifierNoRuling: w } : {}))(readApprovalClassifierNoRuling(frame)),
|
|
1087
1299
|
});
|
|
1300
|
+
if (hold.superseded !== undefined) {
|
|
1301
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} was settled by the engine while its card was up${hold.superseded.parked ? ' (parked)' : ''} — card withdrawn; ` +
|
|
1302
|
+
`the card came back ${card.kind}; nothing sent`);
|
|
1303
|
+
if (hold.superseded.parked && (card.kind === 'allow' || card.kind === 'deny'))
|
|
1304
|
+
surfaceApprovalParking();
|
|
1305
|
+
return { decision: 'unresolved', retracted: true };
|
|
1306
|
+
}
|
|
1088
1307
|
if (argsNotRealInput && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
1089
1308
|
hostLog('error', `liveToolApprovalWire: ${approvalId} card returned an edited approval on a card whose arguments are not the tool's real input (${lane?.argsUnavailable === true ? 'args-unavailable ask' : 'arguments omitted or absent on the frame'}) — nothing sent (the ask stays pending)`);
|
|
1090
1309
|
surfaceEditRefusedOnBlindAsk();
|
|
@@ -1094,6 +1313,22 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1094
1313
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} card retracted without a decision${card.reason ? ` (${card.reason})` : ''} — nothing sent`);
|
|
1095
1314
|
return { decision: 'unresolved', retracted: true };
|
|
1096
1315
|
}
|
|
1316
|
+
if (card.kind === 'aborted') {
|
|
1317
|
+
hold.phase = 'respond';
|
|
1318
|
+
const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
|
|
1319
|
+
let interruptDeny;
|
|
1320
|
+
try {
|
|
1321
|
+
interruptDeny = Promise.resolve(respond(approvalId, 'deny', interruptOpts));
|
|
1322
|
+
}
|
|
1323
|
+
catch (e) {
|
|
1324
|
+
interruptDeny = Promise.reject(e);
|
|
1325
|
+
}
|
|
1326
|
+
hold.trailing = interruptDeny.then(() => undefined, () => undefined);
|
|
1327
|
+
observeCancelByDeny(interruptDeny, approvalId);
|
|
1328
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} card aborted — one tool-level deny issued to settle the pending ask`);
|
|
1329
|
+
return { decision: 'unresolved', aborted: true };
|
|
1330
|
+
}
|
|
1331
|
+
hold.phase = 'respond';
|
|
1097
1332
|
const decision = card.kind === 'allow' ? (card.allowSession ? 'allow_session' : 'allow') : 'deny';
|
|
1098
1333
|
const denySettledByForWire = card.kind === 'deny' ? readApprovalDenySettledBy(card) : undefined;
|
|
1099
1334
|
const attributionKeys = decision === 'deny' ? decisionAttributionKeyOf(decidedByReading, denySettledByForWire) : {};
|
package/dist/humanTurnRead.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ImageInput } from './imagesWireCaps.js';
|
|
2
|
-
import type { UserAttachmentDescriptor, UserAttachmentNotIncludedReason, UserAttachmentSource } from './userAttachmentEnvelope.js';
|
|
2
|
+
import type { UserAttachmentDescriptor, UserAttachmentMcpResourcePart, UserAttachmentNotIncludedReason, UserAttachmentSource } from './userAttachmentEnvelope.js';
|
|
3
3
|
import type { HumanTurnAttachment, HumanTurnEncoding, HumanTurnInput, HumanTurnMissing } from './humanTurn.js';
|
|
4
4
|
import type { ImageVision } from './liveModelCatalog.js';
|
|
5
5
|
export interface CellView {
|
|
@@ -55,6 +55,20 @@ export type DescriptorView = {
|
|
|
55
55
|
path: string;
|
|
56
56
|
sizeBytes: number | null;
|
|
57
57
|
reason: UserAttachmentNotIncludedReason;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'not-included';
|
|
60
|
+
target: 'mcp-resource';
|
|
61
|
+
server: string;
|
|
62
|
+
uri: string;
|
|
63
|
+
name: string;
|
|
64
|
+
reason: UserAttachmentNotIncludedReason;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'mcp-resource';
|
|
67
|
+
server: string;
|
|
68
|
+
uri: string;
|
|
69
|
+
name: string;
|
|
70
|
+
parts: UserAttachmentMcpResourcePart[];
|
|
71
|
+
truncated: boolean;
|
|
58
72
|
};
|
|
59
73
|
export declare function readDescriptor(x: UserAttachmentDescriptor | HumanTurnAttachment['descriptor'], imageDelivery: 'required' | 'ignored'): DescriptorView | undefined;
|
|
60
74
|
type Reason = Exclude<Extract<HumanTurnEncoding, {
|
package/dist/humanTurnRead.js
CHANGED
|
@@ -40,6 +40,23 @@ const strArray = (v) => ownArray(v).map(str);
|
|
|
40
40
|
const sizeOf = (v) => (v === null ? null : typeof v === 'number' ? v : bad());
|
|
41
41
|
const posInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 1 ? v : bad());
|
|
42
42
|
const natInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : bad());
|
|
43
|
+
const NOT_INCLUDED_REASON_LIST = ['too-large', 'unreadable', 'read-denied', 'approval-required', 'server-not-connected', 'resource-not-listed', 'read-failed'];
|
|
44
|
+
const notIncludedReasonsExhaustive = true;
|
|
45
|
+
void notIncludedReasonsExhaustive;
|
|
46
|
+
const NOT_INCLUDED_REASONS = new Set(NOT_INCLUDED_REASON_LIST);
|
|
47
|
+
function readMcpPart(x) {
|
|
48
|
+
if (!isPlainObject(x))
|
|
49
|
+
bad();
|
|
50
|
+
const o = x;
|
|
51
|
+
const kind = ownData(o, 'kind');
|
|
52
|
+
if (kind === 'text')
|
|
53
|
+
return { kind, text: str(ownData(o, 'text')) };
|
|
54
|
+
if (kind === 'binary') {
|
|
55
|
+
const mt = ownData(o, 'mimeType');
|
|
56
|
+
return { kind, mimeType: mt === null ? null : str(mt) };
|
|
57
|
+
}
|
|
58
|
+
return bad();
|
|
59
|
+
}
|
|
43
60
|
function sourceOf(v) {
|
|
44
61
|
return v === 'at-mention' || v === 'compact-restore' ? v : bad();
|
|
45
62
|
}
|
|
@@ -120,9 +137,12 @@ function readDescriptorAny(x, imageDelivery) {
|
|
|
120
137
|
case 'not-included': {
|
|
121
138
|
const target = ownData(o, 'target');
|
|
122
139
|
const reason = ownData(o, 'reason');
|
|
123
|
-
if (
|
|
140
|
+
if (!NOT_INCLUDED_REASONS.has(reason))
|
|
124
141
|
bad();
|
|
125
|
-
if (
|
|
142
|
+
if (target === 'mcp-resource') {
|
|
143
|
+
return { kind, target, server: str(ownData(o, 'server')), uri: str(ownData(o, 'uri')), name: name(), reason: reason };
|
|
144
|
+
}
|
|
145
|
+
if (target !== 'file' && target !== 'directory' && target !== 'path')
|
|
126
146
|
bad();
|
|
127
147
|
return {
|
|
128
148
|
kind,
|
|
@@ -133,6 +153,12 @@ function readDescriptorAny(x, imageDelivery) {
|
|
|
133
153
|
reason: reason,
|
|
134
154
|
};
|
|
135
155
|
}
|
|
156
|
+
case 'mcp-resource': {
|
|
157
|
+
const truncated = ownData(o, 'truncated');
|
|
158
|
+
if (typeof truncated !== 'boolean')
|
|
159
|
+
bad();
|
|
160
|
+
return { kind, server: str(ownData(o, 'server')), uri: str(ownData(o, 'uri')), name: name(), parts: ownArray(ownData(o, 'parts')).map(readMcpPart), truncated: truncated };
|
|
161
|
+
}
|
|
136
162
|
default:
|
|
137
163
|
return undefined;
|
|
138
164
|
}
|