@sema-agent/client-core 0.110.0 → 0.112.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 +244 -0
- package/README.md +59 -18
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +25 -4
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/checkpointRowVerdict.d.ts +3 -0
- package/dist/checkpointRowVerdict.js +14 -1
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/consoleCaPin.d.ts +136 -0
- package/dist/consoleCaPin.js +827 -0
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/deviceRebind.js +3 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +6 -0
- package/dist/effectiveFacts.d.ts +9 -0
- package/dist/effectiveFacts.js +33 -0
- package/dist/engineAddress.d.ts +1 -0
- package/dist/engineAddress.js +4 -1
- package/dist/engineCredentialRelease.d.ts +54 -0
- package/dist/engineCredentialRelease.js +146 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineHealthProbeVerdict.d.ts +24 -0
- package/dist/engineHealthProbeVerdict.js +123 -0
- package/dist/engineNoticeCodes.js +5 -7
- package/dist/engineRepoint.d.ts +12 -5
- package/dist/engineRepoint.js +44 -19
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +11 -1
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +45 -0
- package/dist/engineUnavailable.js +496 -0
- package/dist/engineUrl.js +4 -2
- package/dist/eventLeg.js +3 -3
- package/dist/gateFailureCodes.js +2 -2
- package/dist/generated/sdkFactTables.d.ts +2 -1
- package/dist/generated/sdkFactTables.js +14 -0
- package/dist/generated/settingsSchemaFns.d.ts +1 -0
- package/dist/generated/settingsSchemaFns.js +3 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
- package/dist/generated/settingsSchemaTables.d.ts +56 -0
- package/dist/generated/settingsSchemaTables.js +19 -0
- package/dist/generated/settingsSchemaTypes.d.ts +23 -13
- package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlShape.js +17 -0
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalResolution.d.ts +1 -1
- package/dist/hitl/approvalResolution.js +2 -1
- package/dist/hitl/askGateWire.js +5 -6
- package/dist/hitl/decisionRefusal.d.ts +6 -0
- package/dist/hitl/decisionRefusal.js +19 -10
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +7 -0
- package/dist/hitl/decisionSend.js +34 -12
- package/dist/hitl/editedApprovalAcceptance.js +1 -1
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +8 -15
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/hitlBridge.d.ts +6 -0
- package/dist/hitl/hitlBridge.js +10 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -1
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/localAllowRedemption.d.ts +70 -0
- package/dist/hitl/localAllowRedemption.js +276 -0
- package/dist/hitl/parkOwnership.js +2 -1
- package/dist/hitl/parkResolver.js +14 -4
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +70 -0
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +23 -6
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +363 -0
- package/dist/hitl/sessionPolicyWire.js +2 -2
- package/dist/hitl/standingRows.d.ts +6 -2
- package/dist/hitl/standingRows.js +27 -2
- package/dist/hitl/toolApprovalWire.d.ts +30 -8
- package/dist/hitl/toolApprovalWire.js +264 -121
- package/dist/hooksReaderGenerations.js +1 -1
- package/dist/hooksWireCaps.js +3 -3
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +3 -0
- package/dist/hostTurnSettings.js +38 -5
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +292 -0
- package/dist/i18n/messages.en.js +298 -7
- package/dist/i18n/messages.zh.js +316 -6
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +71 -20
- package/dist/index.js +44 -13
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/liveModelCatalog.d.ts +4 -0
- package/dist/liveModelCatalog.js +12 -3
- package/dist/localConfig/documents.d.ts +61 -0
- package/dist/localConfig/documents.js +51 -0
- package/dist/localConfig/kernel.d.ts +149 -0
- package/dist/localConfig/kernel.js +597 -0
- package/dist/localConfig/mcp/edit.d.ts +161 -0
- package/dist/localConfig/mcp/edit.js +846 -0
- package/dist/localConfig/mcp/servers.d.ts +165 -0
- package/dist/localConfig/mcp/servers.js +776 -0
- package/dist/localConfig/mcp/views.d.ts +170 -0
- package/dist/localConfig/mcp/views.js +429 -0
- package/dist/localConfig/modelPool.d.ts +262 -0
- package/dist/localConfig/modelPool.js +1489 -0
- package/dist/localConfig/modelPoolWords.d.ts +13 -0
- package/dist/localConfig/modelPoolWords.js +20 -0
- package/dist/localConfig/receiptShape.d.ts +7 -0
- package/dist/localConfig/receiptShape.js +135 -0
- package/dist/localConfig/settingsWrite.d.ts +127 -0
- package/dist/localConfig/settingsWrite.js +237 -0
- package/dist/localConfig/skills.d.ts +124 -0
- package/dist/localConfig/skills.js +397 -0
- package/dist/localConfig/skillsWords.d.ts +10 -0
- package/dist/localConfig/skillsWords.js +5 -0
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- package/dist/mcpProbeWire.js +2 -1
- package/dist/mcpReconnect.js +3 -3
- package/dist/mcpWireCaps.js +1 -1
- package/dist/memoryVerbsWire.js +3 -2
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/onboardJudgement.d.ts +14 -4
- package/dist/model/onboardJudgement.js +91 -139
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +3 -40
- package/dist/modelConfigGapNotice.d.ts +20 -0
- package/dist/modelConfigGapNotice.js +102 -0
- package/dist/modsKernelIdentity.js +2 -47
- package/dist/notifications.d.ts +19 -0
- package/dist/notifications.js +114 -12
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +71 -8
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +3 -1
- package/dist/permissionsDeclaration.js +33 -9
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +9 -1
- package/dist/pluginHooksWire.js +40 -6
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +12 -7
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/request/taskRequest.js +10 -6
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +12 -4
- package/dist/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runLedgerSnapshot.js +3 -3
- package/dist/runPermissionModeSwitch.js +3 -4
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +16 -2
- package/dist/seam.js +10 -0
- package/dist/seatContract.d.ts +259 -9
- package/dist/seatContract.js +444 -15
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +4 -1
- package/dist/sessionMemoryErase.js +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.js +8 -9
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sha256Bytes.d.ts +1 -0
- package/dist/sha256Bytes.js +46 -0
- package/dist/skillOverrideChain.d.ts +83 -0
- package/dist/skillOverrideChain.js +378 -0
- package/dist/skillsWireCaps.d.ts +3 -0
- package/dist/skillsWireCaps.js +16 -1
- package/dist/sseIdleTriage.js +2 -1
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +2 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/turnFailurePresentation.js +4 -10
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +141 -19
- package/dist/wireRefusalCopy.d.ts +6 -5
- package/dist/wireRefusalCopy.js +49 -92
- package/docs/INTEGRATION-CLIENTS.md +2718 -17
- package/package.json +7 -3
|
@@ -5,6 +5,7 @@ import { allowRulesGate, allowWireForm } from './permissionsAllowGrantCapability
|
|
|
5
5
|
import { SETTINGS_IS_AT_LEAST } from './generated/settingsSchemaFns.js';
|
|
6
6
|
import { THROWN_SLOT_UNREADABLE, asAssemblyRefusal, assemblyRefusalOf, isSlotCarrier, readThrownSlot, withAssemblyRefusal } from './wireFailureShape.js';
|
|
7
7
|
import { appendOwnElement } from './ownKey.js';
|
|
8
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
8
9
|
const SETTINGS_SOURCE_TIERS = Object.freeze({
|
|
9
10
|
policySettings: 'managed',
|
|
10
11
|
flagSettings: 'global',
|
|
@@ -530,7 +531,24 @@ function allowHeldBySettingsReadCount(report) {
|
|
|
530
531
|
}
|
|
531
532
|
return n;
|
|
532
533
|
}
|
|
533
|
-
|
|
534
|
+
const ALLOW_KEPT_MANAGED_KEYS = Object.freeze({
|
|
535
|
+
in_progress: Object.freeze({ one: 'session.hostSettings.allowKept.managed.inProgress.one', other: 'session.hostSettings.allowKept.managed.inProgress.other' }),
|
|
536
|
+
failed: Object.freeze({ one: 'session.hostSettings.allowKept.managed.failed.one', other: 'session.hostSettings.allowKept.managed.failed.other' }),
|
|
537
|
+
unknown: Object.freeze({ one: 'session.hostSettings.allowKept.managed.unknown.one', other: 'session.hostSettings.allowKept.managed.unknown.other' }),
|
|
538
|
+
});
|
|
539
|
+
const ALLOW_KEPT_GENERIC_KEYS = Object.freeze({
|
|
540
|
+
one: 'session.hostSettings.allowKept.generic.one',
|
|
541
|
+
other: 'session.hostSettings.allowKept.generic.other',
|
|
542
|
+
});
|
|
543
|
+
const ALLOW_KEPT_COUNTED_KEYS = Object.freeze({
|
|
544
|
+
one: 'session.hostSettings.allowKept.why.counted.one',
|
|
545
|
+
other: 'session.hostSettings.allowKept.why.counted.other',
|
|
546
|
+
});
|
|
547
|
+
const ALLOW_KEPT_COUNTED_WHERE_KEYS = Object.freeze({
|
|
548
|
+
one: 'session.hostSettings.allowKept.why.countedWhere.one',
|
|
549
|
+
other: 'session.hostSettings.allowKept.why.countedWhere.other',
|
|
550
|
+
});
|
|
551
|
+
export function permissionsAllowKeptNotice(report, settingsRead, facts, lang) {
|
|
534
552
|
const held = allowHeldBySettingsReadCount(report);
|
|
535
553
|
if (held <= 0)
|
|
536
554
|
return undefined;
|
|
@@ -543,16 +561,22 @@ export function permissionsAllowKeptNotice(report, settingsRead, facts) {
|
|
|
543
561
|
const rawCount = readFact('problemCount');
|
|
544
562
|
const rawWhere = readFact('where');
|
|
545
563
|
const managedPending = readFact('managedPolicyPending') === true;
|
|
564
|
+
const rawFetch = readFact('managedPolicyFetch');
|
|
565
|
+
const fetchState = rawFetch === 'in_progress' || rawFetch === 'failed' ? rawFetch : 'unknown';
|
|
546
566
|
const count = typeof rawCount === 'number' && Number.isInteger(rawCount) && rawCount >= 1 ? rawCount : undefined;
|
|
547
567
|
const where = typeof rawWhere === 'string' && rawWhere.length >= 1 && rawWhere.length <= 200 && !/\p{Cc}/u.test(rawWhere) ? rawWhere : undefined;
|
|
548
|
-
const
|
|
568
|
+
const plural = held === 1 ? 'one' : 'other';
|
|
549
569
|
if (settingsRead === 'partial' && managedPending && count === 1) {
|
|
550
|
-
return (
|
|
551
|
-
'Run again once it has been received (deny and ask rules, and rules given with --allowedTools, are still sent).');
|
|
570
|
+
return renderMessage(msg(ALLOW_KEPT_MANAGED_KEYS[fetchState][plural], { held }), lang);
|
|
552
571
|
}
|
|
553
|
-
const why = settingsRead
|
|
554
|
-
?
|
|
555
|
-
:
|
|
556
|
-
|
|
557
|
-
|
|
572
|
+
const why = settingsRead !== 'partial'
|
|
573
|
+
? msg('session.hostSettings.allowKept.why.unreadable')
|
|
574
|
+
: count === undefined
|
|
575
|
+
? where === undefined
|
|
576
|
+
? msg('session.hostSettings.allowKept.why.problems')
|
|
577
|
+
: msg('session.hostSettings.allowKept.why.problemsWhere', { where })
|
|
578
|
+
: where === undefined
|
|
579
|
+
? msg(ALLOW_KEPT_COUNTED_KEYS[count === 1 ? 'one' : 'other'], { count })
|
|
580
|
+
: msg(ALLOW_KEPT_COUNTED_WHERE_KEYS[count === 1 ? 'one' : 'other'], { count, where });
|
|
581
|
+
return renderMessage(msg(ALLOW_KEPT_GENERIC_KEYS[plural], { held, why }), lang);
|
|
558
582
|
}
|
|
@@ -16,6 +16,7 @@ export interface PlanReviewCardFacts {
|
|
|
16
16
|
readonly taskId: string;
|
|
17
17
|
readonly checkpointId?: string;
|
|
18
18
|
readonly body: PlanReviewBody;
|
|
19
|
+
readonly evidenceRevision?: number;
|
|
19
20
|
}
|
|
20
21
|
export declare function planReviewBodyOf(text: string): Exclude<PlanReviewBody, {
|
|
21
22
|
kind: 'unknown';
|
|
@@ -91,10 +92,12 @@ export interface PlanBodyClaimLeg {
|
|
|
91
92
|
}>;
|
|
92
93
|
overflow: boolean;
|
|
93
94
|
unreadable: boolean;
|
|
95
|
+
readonly seen: Set<string>;
|
|
94
96
|
}
|
|
95
97
|
export declare function openPlanBodyClaimLeg(): PlanBodyClaimLeg;
|
|
96
98
|
export declare function stepPlanBodyClaim(leg: PlanBodyClaimLeg, frame: object, subFlow: boolean): void;
|
|
97
99
|
export declare function planReviewParkFacts(leg: PlanBodyClaimLeg, result: {} | null | undefined): PlanReviewCardFacts | undefined;
|
|
100
|
+
export declare function planReviewClaimStep(leg: PlanBodyClaimLeg, frame: object, subFlow: boolean, seq: string | undefined): PlanReviewCardFacts | undefined;
|
|
98
101
|
export interface PlanReviewFactsTaken {
|
|
99
102
|
readonly sessionKey: string;
|
|
100
103
|
readonly taskId: string;
|
|
@@ -3,6 +3,7 @@ import { readRunTerminal, runTerminalGateKind } from './runTerminal.js';
|
|
|
3
3
|
import { SDK_PLAN_REVIEW_GATE_KINDS } from './generated/sdkFactTables.js';
|
|
4
4
|
import { CORE_PRESENT_PLAN_TOOL_NAME } from './generated/engineFactTables.js';
|
|
5
5
|
import { DEFAULT_SESSION_KEY } from './sessionSlot.js';
|
|
6
|
+
import { doneResultView } from './replayBody.js';
|
|
6
7
|
const PLAN_BODY_MAX_LENGTH = 200_000;
|
|
7
8
|
const PLAN_BODY_UNKNOWN_CAUSES = Object.freeze([
|
|
8
9
|
'not_observed', 'gate_unidentified', 'gate_moved', 'unreadable', 'ambiguous_call', 'malformed_frame', 'conflicting_claims', 'not_presented', 'not_carried',
|
|
@@ -29,6 +30,13 @@ export function mintPlanReviewCardFacts(taskId, checkpointId, body) {
|
|
|
29
30
|
const b = checkpointId === undefined ? unknownBody('gate_unidentified') : body;
|
|
30
31
|
return Object.freeze({ taskId, ...(checkpointId !== undefined ? { checkpointId } : {}), body: Object.isFrozen(b) ? b : Object.freeze({ ...b }) });
|
|
31
32
|
}
|
|
33
|
+
let evidenceRevisionSeq = 0;
|
|
34
|
+
function withEvidenceRevision(facts, evidenceRevision) {
|
|
35
|
+
return Object.freeze({ taskId: facts.taskId, ...(facts.checkpointId !== undefined ? { checkpointId: facts.checkpointId } : {}), body: facts.body, evidenceRevision });
|
|
36
|
+
}
|
|
37
|
+
function isEvidenceRevision(v) {
|
|
38
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
|
|
39
|
+
}
|
|
32
40
|
export function unknownBody(cause) {
|
|
33
41
|
return Object.freeze({ kind: 'unknown', cause });
|
|
34
42
|
}
|
|
@@ -59,7 +67,11 @@ export function planReviewCardFactsFrom(v) {
|
|
|
59
67
|
const checkpointId = ck.present ? ck.value : undefined;
|
|
60
68
|
if (checkpointId === undefined && !(body.kind === 'unknown' && body.cause === 'gate_unidentified'))
|
|
61
69
|
return undefined;
|
|
62
|
-
|
|
70
|
+
const eg = ownData(v, 'evidenceRevision');
|
|
71
|
+
if (eg.present && !isEvidenceRevision(eg.value))
|
|
72
|
+
return undefined;
|
|
73
|
+
const minted = mintPlanReviewCardFacts(taskId, checkpointId, body);
|
|
74
|
+
return eg.present ? withEvidenceRevision(minted, eg.value) : minted;
|
|
63
75
|
}
|
|
64
76
|
catch {
|
|
65
77
|
return undefined;
|
|
@@ -167,6 +179,10 @@ export function commitPlanReviewFacts(ticket, facts, claim, highWater) {
|
|
|
167
179
|
if (prev !== undefined && prev.checkpointId === checkpointId && (isConflict(prev.facts) || !samePlanClaim(prev.claim, claim))) {
|
|
168
180
|
out = mintPlanReviewCardFacts(facts.taskId, checkpointId, unknownBody('conflicting_claims'));
|
|
169
181
|
}
|
|
182
|
+
const reused = prev !== undefined && prev.checkpointId === checkpointId && prev.facts.evidenceRevision !== undefined && samePlanReviewCardFacts(prev.facts, out)
|
|
183
|
+
? prev.facts.evidenceRevision
|
|
184
|
+
: undefined;
|
|
185
|
+
out = withEvidenceRevision(out, reused ?? ++evidenceRevisionSeq);
|
|
170
186
|
rec.gate = { checkpointId, facts: out, claim, generation: ticket.generation, ...(highWater !== undefined ? { highWater } : {}) };
|
|
171
187
|
return out;
|
|
172
188
|
}
|
|
@@ -338,7 +354,7 @@ function foldMarker(rec, frame) {
|
|
|
338
354
|
}
|
|
339
355
|
const LEG_BUFFER_MAX = 256;
|
|
340
356
|
export function openPlanBodyClaimLeg() {
|
|
341
|
-
return { buffer: [], overflow: false, unreadable: false };
|
|
357
|
+
return { buffer: [], overflow: false, unreadable: false, seen: new Set() };
|
|
342
358
|
}
|
|
343
359
|
function bindLeg(leg, taskId) {
|
|
344
360
|
const rec = recordFor(DEFAULT_SESSION_KEY, taskId);
|
|
@@ -425,6 +441,40 @@ export function planReviewParkFacts(leg, result) {
|
|
|
425
441
|
return taskId === undefined ? undefined : mintPlanReviewCardFacts(taskId, checkpointId, unknownBody('unreadable'));
|
|
426
442
|
}
|
|
427
443
|
}
|
|
444
|
+
export function planReviewClaimStep(leg, frame, subFlow, seq) {
|
|
445
|
+
if (claimSeqDedupe(leg, frame, seq) === 'duplicate')
|
|
446
|
+
return undefined;
|
|
447
|
+
stepPlanBodyClaim(leg, frame, subFlow);
|
|
448
|
+
let result;
|
|
449
|
+
try {
|
|
450
|
+
if (frame.type !== 'done')
|
|
451
|
+
return undefined;
|
|
452
|
+
result = frame.result;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
return planReviewParkFacts(leg, doneResultView(result).body);
|
|
458
|
+
}
|
|
459
|
+
function claimSeqDedupe(leg, frame, seq) {
|
|
460
|
+
try {
|
|
461
|
+
if (seq !== undefined && classOf(frame) !== 'other') {
|
|
462
|
+
if (leg.seen.has(seq))
|
|
463
|
+
return 'duplicate';
|
|
464
|
+
leg.seen.add(seq);
|
|
465
|
+
while (leg.seen.size > SETTLED_CALLS_MAX) {
|
|
466
|
+
const oldest = leg.seen.values().next();
|
|
467
|
+
if (oldest.done === true)
|
|
468
|
+
break;
|
|
469
|
+
leg.seen.delete(oldest.value);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return 'fresh';
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
return 'class_unreadable';
|
|
476
|
+
}
|
|
477
|
+
}
|
|
428
478
|
function legRecord(leg, taskId) {
|
|
429
479
|
return leg.taskId === undefined || leg.taskId === taskId ? bindLeg(leg, taskId) : recordFor(DEFAULT_SESSION_KEY, taskId);
|
|
430
480
|
}
|
|
@@ -12,8 +12,10 @@ export declare const PLUGIN_HOOK_REASONS: readonly ["projected", "shell_event",
|
|
|
12
12
|
export type PluginHookReason = (typeof PLUGIN_HOOK_REASONS)[number];
|
|
13
13
|
export declare const PLUGIN_HOOK_EXCLUSION_REASONS: readonly ["workspace_untrusted", "governance_unreadable", "policy_disable_all", "startup_mode", "managed_plugins_only", "prompt_not_user_authored"];
|
|
14
14
|
export type PluginHookExclusionReason = (typeof PLUGIN_HOOK_EXCLUSION_REASONS)[number];
|
|
15
|
-
export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported", "key_not_read", "source_not_authored", "workspace_untrusted", "governance_unreadable", "policy_disable_all"];
|
|
15
|
+
export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported", "key_not_read", "source_not_authored", "workspace_untrusted", "governance_unreadable", "policy_disable_all", "no_executor"];
|
|
16
16
|
export type SettingsHookDropReason = (typeof SETTINGS_HOOK_DROP_REASONS)[number];
|
|
17
|
+
export type HookEntryTypeWord = 'command' | 'prompt' | 'agent' | 'http' | 'mcp_tool';
|
|
18
|
+
export declare const HOOK_ENTRY_TYPE_WORDS: readonly ["command", "prompt", "agent", "http", "mcp_tool"];
|
|
17
19
|
export type HookSettingsSource = 'policySettings' | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings';
|
|
18
20
|
export interface PluginHookKey {
|
|
19
21
|
readonly pluginId: string;
|
|
@@ -34,6 +36,7 @@ export interface SettingsHookDrop {
|
|
|
34
36
|
readonly event: string;
|
|
35
37
|
readonly groupIndex: number;
|
|
36
38
|
readonly hookIndex: number;
|
|
39
|
+
readonly type?: HookEntryTypeWord;
|
|
37
40
|
readonly reason: SettingsHookDropReason;
|
|
38
41
|
readonly notRun: boolean;
|
|
39
42
|
readonly unreadKeys?: readonly (readonly (string | number)[])[];
|
|
@@ -43,6 +46,7 @@ export interface SettingsHookVerdict {
|
|
|
43
46
|
readonly event: string;
|
|
44
47
|
readonly groupIndex: number;
|
|
45
48
|
readonly hookIndex: number;
|
|
49
|
+
readonly type?: HookEntryTypeWord;
|
|
46
50
|
readonly disposition: PluginHookDisposition;
|
|
47
51
|
readonly reason: PluginHookReason;
|
|
48
52
|
}
|
|
@@ -51,6 +55,7 @@ export interface SettingsHookExclusion {
|
|
|
51
55
|
readonly event: string;
|
|
52
56
|
readonly groupIndex: number;
|
|
53
57
|
readonly hookIndex: number;
|
|
58
|
+
readonly type?: HookEntryTypeWord;
|
|
54
59
|
readonly reason: PluginHookExclusionReason;
|
|
55
60
|
}
|
|
56
61
|
export interface SettingsHooksSalvageRow {
|
|
@@ -169,6 +174,9 @@ export declare function decideSessionHooks(input: SessionHookDecisionInput): {
|
|
|
169
174
|
readonly unreadable: number;
|
|
170
175
|
};
|
|
171
176
|
export declare function filterSettingsHookGroups(source: HookSettingsSource, event: string, groups: readonly WireHookGroup[], execFormCapable: boolean, shellRunsType: (type: string | undefined) => boolean, judge: SettingsHookJudge, readerNotRead: readonly string[], mask?: HooksSalvageMask): SettingsHookFilterResult;
|
|
177
|
+
export declare function hookEntryTypeWordOf(entry: {} | null | undefined): {
|
|
178
|
+
readonly type?: HookEntryTypeWord;
|
|
179
|
+
};
|
|
172
180
|
export interface SettingsHookFilterResult {
|
|
173
181
|
readonly groups: WireHookGroup[];
|
|
174
182
|
readonly drops: SettingsHookDrop[];
|
package/dist/pluginHooksWire.js
CHANGED
|
@@ -3,6 +3,7 @@ import { appendOwnElement, readOwnDataValue } from './ownKey.js';
|
|
|
3
3
|
import { inSlotReadOf } from './wireFailureShape.js';
|
|
4
4
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
5
|
import { SETTINGS_ENGINE_OWNED_HOOK_EVENTS } from './generated/settingsSchemaTables.js';
|
|
6
|
+
import { SETTINGS_HOOK_EVENTS } from './generated/settingsSchemaFns.js';
|
|
6
7
|
import { HOOK_SETTINGS_SOURCE_TEXT, hooksEntryUnreadKeys, hooksGroupAuthoredSource, hooksGroupUnreadKeys, hooksKeyCoordinateText, hooksSalvageMaskOf, salvageSettingsHooksEntries, } from './settingsHooksSalvage.js';
|
|
7
8
|
export const ENGINE_FIRED_HOOK_EVENTS = SETTINGS_ENGINE_OWNED_HOOK_EVENTS;
|
|
8
9
|
export const PLUGIN_HOOK_DISPOSITIONS = ['engine', 'shell', 'not_run'];
|
|
@@ -49,7 +50,11 @@ export const SETTINGS_HOOK_DROP_REASONS = [
|
|
|
49
50
|
'workspace_untrusted',
|
|
50
51
|
'governance_unreadable',
|
|
51
52
|
'policy_disable_all',
|
|
53
|
+
'no_executor',
|
|
52
54
|
];
|
|
55
|
+
export const HOOK_ENTRY_TYPE_WORDS = Object.freeze(['command', 'prompt', 'agent', 'http', 'mcp_tool']);
|
|
56
|
+
const _hookEntryTypePins = [true, true, true, true];
|
|
57
|
+
void _hookEntryTypePins;
|
|
53
58
|
export function hooksWirePlanShapeOf(v) {
|
|
54
59
|
try {
|
|
55
60
|
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
@@ -144,6 +149,7 @@ function hookExecutorOf(x) {
|
|
|
144
149
|
return judged(x.shellRuns ? 'shell' : 'not_run', why);
|
|
145
150
|
}
|
|
146
151
|
const ENGINE_EVENTS = new Set(ENGINE_FIRED_HOOK_EVENTS);
|
|
152
|
+
const SHELL_OWNED_EVENTS = new Set(SETTINGS_HOOK_EVENTS.filter((e) => !ENGINE_EVENTS.has(e)));
|
|
147
153
|
const USER_CONFIG_REF_ONE = /\$\{user_config\.[^}]+\}/;
|
|
148
154
|
const USER_CONFIG_REF_ALL = /\$\{user_config\.([^}]+)\}/g;
|
|
149
155
|
function isRecord(v) {
|
|
@@ -493,10 +499,23 @@ export function filterSettingsHookGroups(source, event, groups, execFormCapable,
|
|
|
493
499
|
const excluded = [];
|
|
494
500
|
const out = [];
|
|
495
501
|
let stripped = 0;
|
|
496
|
-
const engineEvent =
|
|
502
|
+
const engineEvent = isEngineFiredHookEvent(event);
|
|
503
|
+
const shellOwned = !engineEvent && SHELL_OWNED_EVENTS.has(event);
|
|
497
504
|
groups.forEach((group, groupIndex) => {
|
|
498
505
|
if (mask !== undefined && mask.groupDropped(event, groupIndex))
|
|
499
506
|
return;
|
|
507
|
+
if (!engineEvent) {
|
|
508
|
+
if (!shellOwned || !isRecord(group) || !Array.isArray(group.hooks))
|
|
509
|
+
return;
|
|
510
|
+
group.hooks.forEach((entry, hookIndex) => {
|
|
511
|
+
if (mask !== undefined && mask.entryDropped(event, groupIndex, hookIndex))
|
|
512
|
+
return;
|
|
513
|
+
if (shellRunsType(isRecord(entry) && typeof entry.type === 'string' ? entry.type : undefined))
|
|
514
|
+
return;
|
|
515
|
+
appendOwnElement(drops, { source, event, groupIndex, hookIndex, reason: 'no_executor', notRun: true });
|
|
516
|
+
});
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
500
519
|
if (!isRecord(group) || !Array.isArray(group.hooks)) {
|
|
501
520
|
appendOwnElement(out, group);
|
|
502
521
|
return;
|
|
@@ -522,27 +541,29 @@ export function filterSettingsHookGroups(source, event, groups, execFormCapable,
|
|
|
522
541
|
const sourceNotAuthored = earlier === undefined && groupSourceAuthored && (authored === 'unreadable' || entryUnread !== undefined);
|
|
523
542
|
const unreadKeys = earlier === undefined && !sourceNotAuthored ? unreadKeyPathsOf(event, groupIndex, hookIndex, groupUnread ?? [], entryUnread) : [];
|
|
524
543
|
const reason = earlier ?? (sourceNotAuthored ? 'source_not_authored' : unreadKeys.length > 0 ? 'key_not_read' : undefined);
|
|
544
|
+
const typed = hookEntryTypeWordOf(entry);
|
|
525
545
|
if (reason !== undefined) {
|
|
526
546
|
appendOwnElement(drops, {
|
|
527
547
|
source,
|
|
528
548
|
event,
|
|
529
549
|
groupIndex,
|
|
530
550
|
hookIndex,
|
|
551
|
+
...typed,
|
|
531
552
|
reason,
|
|
532
|
-
notRun:
|
|
553
|
+
notRun: !shellRunsType(isRecord(entry) && typeof entry.type === 'string' ? entry.type : undefined),
|
|
533
554
|
...(reason === 'key_not_read' ? { unreadKeys } : {}),
|
|
534
555
|
});
|
|
535
556
|
changed = true;
|
|
536
557
|
return;
|
|
537
558
|
}
|
|
538
|
-
if (
|
|
559
|
+
if (isRecord(entry) && judgeableSettingsEntry(entry)) {
|
|
539
560
|
const ex = judge(event, group, entry);
|
|
540
561
|
if (ex.kind === 'excluded') {
|
|
541
|
-
appendOwnElement(excluded, { source, event, groupIndex, hookIndex, reason: ex.reason });
|
|
562
|
+
appendOwnElement(excluded, { source, event, groupIndex, hookIndex, ...typed, reason: ex.reason });
|
|
542
563
|
changed = true;
|
|
543
564
|
return;
|
|
544
565
|
}
|
|
545
|
-
appendOwnElement(verdicts, { source, event, groupIndex, hookIndex, disposition: ex.disposition, reason: ex.reason });
|
|
566
|
+
appendOwnElement(verdicts, { source, event, groupIndex, hookIndex, ...typed, disposition: ex.disposition, reason: ex.reason });
|
|
546
567
|
if (ex.disposition === 'shell') {
|
|
547
568
|
changed = true;
|
|
548
569
|
return;
|
|
@@ -567,6 +588,17 @@ export function filterSettingsHookGroups(source, event, groups, execFormCapable,
|
|
|
567
588
|
});
|
|
568
589
|
return { groups: out, drops, stripped, verdicts, excluded };
|
|
569
590
|
}
|
|
591
|
+
export function hookEntryTypeWordOf(entry) {
|
|
592
|
+
try {
|
|
593
|
+
if (!isRecord(entry))
|
|
594
|
+
return {};
|
|
595
|
+
const t = readOwnDataValue(entry, 'type');
|
|
596
|
+
return typeof t === 'string' && HOOK_ENTRY_TYPE_WORDS.includes(t) ? { type: t } : {};
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
return {};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
570
602
|
function judgeableSettingsEntry(entry) {
|
|
571
603
|
const type = entry.type;
|
|
572
604
|
if (typeof type !== 'string' || !ENGINE_HOOK_TYPE_RUNS.has(type))
|
|
@@ -899,7 +931,7 @@ function settingsExclusionRowOf(v) {
|
|
|
899
931
|
const REASON_TEXT = {
|
|
900
932
|
projected: 'it is sent to the engine',
|
|
901
933
|
shell_event: 'this client runs this event itself',
|
|
902
|
-
no_executor: '
|
|
934
|
+
no_executor: renderMessage(msg('config.hooks.plan.reason.noExecutor')),
|
|
903
935
|
engine_not_local: 'the engine was not started by this client on this machine, so it cannot reach the plugin files',
|
|
904
936
|
engine_locality_unknown: 'it is not known whether the engine was started by this client on this machine, so plugin hooks are not sent to it',
|
|
905
937
|
engine_capability_absent: 'the connected engine does not support plugin hooks',
|
|
@@ -931,6 +963,7 @@ const DROP_TEXT = {
|
|
|
931
963
|
workspace_untrusted: renderMessage(msg('config.hooks.plan.reason.closedUntrusted')),
|
|
932
964
|
governance_unreadable: renderMessage(msg('config.hooks.plan.reason.closedGovernanceUnreadable')),
|
|
933
965
|
policy_disable_all: renderMessage(msg('config.hooks.plan.reason.closedDisableAll')),
|
|
966
|
+
no_executor: REASON_TEXT.no_executor,
|
|
934
967
|
};
|
|
935
968
|
const SOURCE_TEXT = HOOK_SETTINGS_SOURCE_TEXT;
|
|
936
969
|
export function pluginHookReasonText(reason) {
|
|
@@ -1011,6 +1044,7 @@ function namedPathsOfRow(d) {
|
|
|
1011
1044
|
case 'workspace_untrusted':
|
|
1012
1045
|
case 'governance_unreadable':
|
|
1013
1046
|
case 'policy_disable_all':
|
|
1047
|
+
case 'no_executor':
|
|
1014
1048
|
return [];
|
|
1015
1049
|
}
|
|
1016
1050
|
}
|
|
@@ -24,6 +24,8 @@ export function toolEndResultToUserFrame(arm) {
|
|
|
24
24
|
}, undefined, parent === null ? 'leader' : 'subagent');
|
|
25
25
|
const envelope = toolResultEnvelopeParts(outcome);
|
|
26
26
|
const gateView = guardedRead(() => gateOutcomeOf(arm));
|
|
27
|
+
const denialKindRaw = arm._sema_denial_kind;
|
|
28
|
+
const denialKind = typeof denialKindRaw === 'string' ? denialKindRaw : undefined;
|
|
27
29
|
const content = Array.isArray(outcome.body.content) ? outcome.body.content : arm.truncated === true ? `${text}\n…(truncated)` : text;
|
|
28
30
|
return {
|
|
29
31
|
type: 'user',
|
|
@@ -39,9 +41,9 @@ export function toolEndResultToUserFrame(arm) {
|
|
|
39
41
|
],
|
|
40
42
|
},
|
|
41
43
|
parent_tool_use_id: parent,
|
|
42
|
-
...(isCcToolDenialKind(
|
|
44
|
+
...(isCcToolDenialKind(denialKind) ? { _sema_denial_kind: denialKind } : {}),
|
|
43
45
|
...(gateView !== undefined ? { _sema_gate: gateView } : {}),
|
|
44
|
-
...toolResultRowFlagParts(arm, gateView),
|
|
46
|
+
...toolResultRowFlagParts(arm, gateView, denialKind),
|
|
45
47
|
...(Object.hasOwn(envelope, 'tool_use_result') ? { tool_use_result: envelope.tool_use_result } : {}),
|
|
46
48
|
...(Object.hasOwn(envelope, '_sema_degraded') ? { _sema_degraded: envelope._sema_degraded } : {}),
|
|
47
49
|
uuid: rowIdentity.uuid,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { displayUntrustedCapped } from './displayUntrusted.js';
|
|
2
2
|
import { stripSystemReminderTagTokens, unwrapSystemReminder } from './systemReminderTag.js';
|
|
3
3
|
import { PROMPT_BLOCKED_BY_HOOK_ROW_LEAD } from './rowKind.js';
|
|
4
4
|
export { PROMPT_BLOCKED_BY_HOOK_ROW_LEAD };
|
|
5
5
|
const RUN_BLOCKED_REASONED = 'Run blocked';
|
|
6
6
|
const RUN_BLOCKED_NO_REASON = 'Run blocked (the agent reported it cannot proceed)';
|
|
7
|
-
const
|
|
7
|
+
const WORDS_SHOWN_MAX = 1000;
|
|
8
|
+
function shownWords(words) {
|
|
9
|
+
return displayUntrustedCapped(words, WORDS_SHOWN_MAX).trim();
|
|
10
|
+
}
|
|
8
11
|
const CAUSE_CLAUSE = Object.freeze({
|
|
9
12
|
crashed: 'the hook failed before it answered; the prompt was not submitted',
|
|
10
13
|
timeout: 'the hook did not answer in time; the prompt was not submitted',
|
|
@@ -13,7 +16,7 @@ const CAUSE_CLAUSE = Object.freeze({
|
|
|
13
16
|
function shownHookWords(words) {
|
|
14
17
|
if (words === undefined)
|
|
15
18
|
return undefined;
|
|
16
|
-
const shown = stripSystemReminderTagTokens(
|
|
19
|
+
const shown = stripSystemReminderTagTokens(shownWords(stripSystemReminderTagTokens(words))).trim();
|
|
17
20
|
return shown === '' ? undefined : shown;
|
|
18
21
|
}
|
|
19
22
|
export function runBlockedText(blocked) {
|
|
@@ -29,8 +32,10 @@ export function runBlockedText(blocked) {
|
|
|
29
32
|
if (reason === undefined)
|
|
30
33
|
return RUN_BLOCKED_NO_REASON;
|
|
31
34
|
const unwrapped = unwrapSystemReminder(reason);
|
|
32
|
-
if (unwrapped === reason)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
if (unwrapped === reason) {
|
|
36
|
+
const shown = shownWords(reason);
|
|
37
|
+
return shown === '' ? RUN_BLOCKED_NO_REASON : `${RUN_BLOCKED_REASONED}: ${shown}`;
|
|
38
|
+
}
|
|
39
|
+
const body = shownHookWords(unwrapped);
|
|
40
|
+
return body === undefined ? RUN_BLOCKED_NO_REASON : `${RUN_BLOCKED_REASONED}: ${body}`;
|
|
36
41
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const SUGGESTION_BATCH_CAP = 8;
|
|
2
|
+
export declare const SUGGESTION_CHARS_CAP = 200;
|
|
3
|
+
export interface PromptSuggestionBatch {
|
|
4
|
+
readonly list: readonly string[];
|
|
5
|
+
readonly truncatedCount?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function promptSuggestionBatchOf(raw: {} | null | undefined): PromptSuggestionBatch | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const SUGGESTION_BATCH_CAP = 8;
|
|
2
|
+
export const SUGGESTION_CHARS_CAP = 200;
|
|
3
|
+
export function promptSuggestionBatchOf(raw) {
|
|
4
|
+
const filtered = (Array.isArray(raw) ? raw : []).filter((s) => typeof s === 'string' && s.trim().length > 0);
|
|
5
|
+
const list = filtered.slice(0, SUGGESTION_BATCH_CAP).map((s) => (s.length > SUGGESTION_CHARS_CAP ? `${s.slice(0, SUGGESTION_CHARS_CAP)}…` : s));
|
|
6
|
+
if (list.length === 0)
|
|
7
|
+
return undefined;
|
|
8
|
+
return { list, ...(filtered.length > list.length ? { truncatedCount: filtered.length - list.length } : {}) };
|
|
9
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AgentClient } from '@sema-agent/sdk';
|
|
2
|
+
import type { LaneProof } from './seam.js';
|
|
3
|
+
export declare const PROMPT_SUGGESTIONS_TAIL_MAX_ATTEMPTS = 6;
|
|
4
|
+
export declare const PROMPT_SUGGESTIONS_TAIL_BUDGET_MS = 12000;
|
|
5
|
+
export interface PromptSuggestionsTailEvent {
|
|
6
|
+
readonly kind: 'prompt_suggestions';
|
|
7
|
+
readonly laneProof: LaneProof;
|
|
8
|
+
readonly suggestions: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
export type PromptSuggestionsStreamSeen = 'frame' | 'done' | 'cut';
|
|
11
|
+
export interface PromptSuggestionsTailInput {
|
|
12
|
+
readonly runs: Pick<AgentClient['runs'], 'get'>;
|
|
13
|
+
readonly runId: string;
|
|
14
|
+
readonly sessionId?: string | undefined;
|
|
15
|
+
readonly requested: boolean;
|
|
16
|
+
readonly stream: PromptSuggestionsStreamSeen;
|
|
17
|
+
readonly baseUrl: string | undefined;
|
|
18
|
+
readonly signal?: AbortSignal | undefined;
|
|
19
|
+
readonly sleep?: ((ms: number) => Promise<void>) | undefined;
|
|
20
|
+
readonly now?: (() => number) | undefined;
|
|
21
|
+
}
|
|
22
|
+
export type PromptSuggestionsTailOutcome = {
|
|
23
|
+
readonly kind: 'skipped';
|
|
24
|
+
readonly why: 'not_requested' | 'frame_on_stream' | 'settled_on_stream';
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: 'settled';
|
|
27
|
+
readonly event?: PromptSuggestionsTailEvent;
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: 'not_completed';
|
|
30
|
+
readonly attempts: number;
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: 'gave_up';
|
|
33
|
+
readonly attempts: number;
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: 'unavailable';
|
|
36
|
+
readonly attempts: number;
|
|
37
|
+
};
|
|
38
|
+
export declare function promptSuggestionsOnStream(baseUrl: string | undefined): boolean;
|
|
39
|
+
export declare function followUpPromptSuggestions(input: PromptSuggestionsTailInput): Promise<PromptSuggestionsTailOutcome>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { abortableSleep, requestDeadline } from './abortableSleep.js';
|
|
2
|
+
import { engineCapString, engineCapValue } from './engineCapsCache.js';
|
|
3
|
+
import { readOwnDataValue } from './ownKey.js';
|
|
4
|
+
import { promptSuggestionBatchOf } from './promptSuggestionBatch.js';
|
|
5
|
+
import { engineVersionTier } from './supportFloor.js';
|
|
6
|
+
export const PROMPT_SUGGESTIONS_TAIL_MAX_ATTEMPTS = 6;
|
|
7
|
+
export const PROMPT_SUGGESTIONS_TAIL_BUDGET_MS = 12_000;
|
|
8
|
+
const RETRY_STEP_MS = 750;
|
|
9
|
+
const RETRY_CAP_MS = 3_000;
|
|
10
|
+
const ON_STREAM_SERVER_FLOOR = '7.149.0';
|
|
11
|
+
const MAY_STILL_SUGGEST = Object.freeze(['completed', 'running']);
|
|
12
|
+
export function promptSuggestionsOnStream(baseUrl) {
|
|
13
|
+
try {
|
|
14
|
+
const bit = engineCapValue(baseUrl, 'promptSuggestions');
|
|
15
|
+
if (bit.kind !== 'value' || bit.value !== true)
|
|
16
|
+
return false;
|
|
17
|
+
return engineVersionTier(engineCapString(baseUrl, 'version'), ON_STREAM_SERVER_FLOOR) === 'engine';
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const freeze = (o) => Object.freeze(o);
|
|
24
|
+
const own = (o, key) => {
|
|
25
|
+
try {
|
|
26
|
+
return typeof o === 'object' && o !== null ? readOwnDataValue(o, key) : undefined;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function eventOf(raw) {
|
|
33
|
+
const batch = promptSuggestionBatchOf(raw);
|
|
34
|
+
return batch === undefined ? undefined : freeze({ kind: 'prompt_suggestions', laneProof: freeze({ lane: 'main' }), suggestions: freeze([...batch.list]) });
|
|
35
|
+
}
|
|
36
|
+
function skipWhy(input) {
|
|
37
|
+
if (own(input, 'requested') !== true)
|
|
38
|
+
return 'not_requested';
|
|
39
|
+
const seen = own(input, 'stream');
|
|
40
|
+
if (seen === 'frame')
|
|
41
|
+
return 'frame_on_stream';
|
|
42
|
+
if (seen === 'done' && promptSuggestionsOnStream(own(input, 'baseUrl')))
|
|
43
|
+
return 'settled_on_stream';
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
export async function followUpPromptSuggestions(input) {
|
|
47
|
+
let attempts = 0;
|
|
48
|
+
try {
|
|
49
|
+
const why = skipWhy(input);
|
|
50
|
+
if (why !== undefined)
|
|
51
|
+
return freeze({ kind: 'skipped', why });
|
|
52
|
+
const runs = own(input, 'runs');
|
|
53
|
+
const runId = own(input, 'runId');
|
|
54
|
+
const get = typeof runs === 'object' && runs !== null ? runs.get : undefined;
|
|
55
|
+
if (typeof get !== 'function' || typeof runId !== 'string' || runId.length === 0)
|
|
56
|
+
return freeze({ kind: 'unavailable', attempts });
|
|
57
|
+
const sessionId = own(input, 'sessionId');
|
|
58
|
+
const signal = own(input, 'signal');
|
|
59
|
+
const sleepIn = own(input, 'sleep');
|
|
60
|
+
const nowIn = own(input, 'now');
|
|
61
|
+
const sleep = typeof sleepIn === 'function' ? sleepIn : (ms) => abortableSleep(ms, signal ?? new AbortController().signal);
|
|
62
|
+
const now = typeof nowIn === 'function' ? nowIn : Date.now;
|
|
63
|
+
const signalState = () => {
|
|
64
|
+
if (signal === undefined || signal === null)
|
|
65
|
+
return 'live';
|
|
66
|
+
try {
|
|
67
|
+
return signal.aborted === true ? 'aborted' : 'live';
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return 'unreadable';
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const t0 = now();
|
|
74
|
+
for (;;) {
|
|
75
|
+
if (signalState() !== 'live')
|
|
76
|
+
return freeze({ kind: 'unavailable', attempts });
|
|
77
|
+
const left = PROMPT_SUGGESTIONS_TAIL_BUDGET_MS - (now() - t0);
|
|
78
|
+
if (!(left > 0))
|
|
79
|
+
return freeze({ kind: 'gave_up', attempts });
|
|
80
|
+
attempts++;
|
|
81
|
+
const d = requestDeadline(left, signal);
|
|
82
|
+
let rec;
|
|
83
|
+
try {
|
|
84
|
+
rec = await d.race(Promise.resolve(get.call(runs, runId, {
|
|
85
|
+
...(typeof sessionId === 'string' && sessionId.length > 0 ? { session: sessionId } : {}),
|
|
86
|
+
signal: d.signal,
|
|
87
|
+
})));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return freeze({ kind: d.expired() ? 'gave_up' : 'unavailable', attempts });
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
d.abort();
|
|
94
|
+
}
|
|
95
|
+
const suggestions = own(rec, 'suggestions');
|
|
96
|
+
if (Array.isArray(suggestions)) {
|
|
97
|
+
const event = eventOf(suggestions);
|
|
98
|
+
return freeze({ kind: 'settled', ...(event !== undefined ? { event } : {}) });
|
|
99
|
+
}
|
|
100
|
+
const status = own(rec, 'status');
|
|
101
|
+
if (typeof status === 'string' && !MAY_STILL_SUGGEST.includes(status))
|
|
102
|
+
return freeze({ kind: 'not_completed', attempts });
|
|
103
|
+
if (attempts >= PROMPT_SUGGESTIONS_TAIL_MAX_ATTEMPTS)
|
|
104
|
+
return freeze({ kind: 'gave_up', attempts });
|
|
105
|
+
const rest = PROMPT_SUGGESTIONS_TAIL_BUDGET_MS - (now() - t0);
|
|
106
|
+
if (!(rest > 0))
|
|
107
|
+
return freeze({ kind: 'gave_up', attempts });
|
|
108
|
+
if (signalState() !== 'live')
|
|
109
|
+
return freeze({ kind: 'unavailable', attempts });
|
|
110
|
+
await sleep(Math.min(RETRY_STEP_MS * attempts, RETRY_CAP_MS, rest));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return freeze({ kind: 'unavailable', attempts });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -548,8 +548,12 @@ export function refilterHostSettings(request, fresh, lane) {
|
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
|
-
|
|
552
|
-
|
|
551
|
+
const nowEnv = intake.carried.env;
|
|
552
|
+
const envUnwired = intake.dispositions['settings.env'] === 'unwired';
|
|
553
|
+
const envMaybeAdded = nowEnv !== undefined && !envUnwired && hostRefuseRowSeated('settings.env', lane, true);
|
|
554
|
+
const hasSentEnv = Object.hasOwn(nextSettings, 'env');
|
|
555
|
+
if (hasSentEnv || envMaybeAdded) {
|
|
556
|
+
const sentEnv = hasSentEnv ? nextSettings.env : {};
|
|
553
557
|
if (!isPlainRecord(sentEnv))
|
|
554
558
|
return unjudged();
|
|
555
559
|
let names;
|
|
@@ -559,14 +563,14 @@ export function refilterHostSettings(request, fresh, lane) {
|
|
|
559
563
|
catch {
|
|
560
564
|
return unjudged();
|
|
561
565
|
}
|
|
562
|
-
const nowEnv = intake.carried.env;
|
|
563
|
-
const envUnwired = intake.dispositions['settings.env'] === 'unwired';
|
|
564
566
|
const sentKeys = Object.keys(sentEnv);
|
|
565
567
|
const kept = sentKeys.filter((k) => names.includes(k) && (envUnwired || (nowEnv !== undefined && Object.hasOwn(nowEnv, k))));
|
|
566
|
-
|
|
568
|
+
const added = envMaybeAdded && nowEnv !== undefined ? names.filter((n) => !sentKeys.includes(n) && Object.hasOwn(nowEnv, n)) : [];
|
|
569
|
+
if (kept.length !== sentKeys.length || added.length > 0) {
|
|
567
570
|
const { env: _sentEnv, ...restSettings } = nextSettings;
|
|
568
571
|
void _sentEnv;
|
|
569
|
-
|
|
572
|
+
const rows = [...kept.map((k) => [k, sentEnv[k]]), ...added.map((n) => [n, nowEnv?.[n]])];
|
|
573
|
+
nextSettings = rows.length === 0 ? restSettings : { ...restSettings, env: Object.fromEntries(rows) };
|
|
570
574
|
}
|
|
571
575
|
}
|
|
572
576
|
if (nextSettings === settings)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function requestCoordinateText(root: string, segs: readonly (string | number)[], label?: (seg: string) => string): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const PLAIN_SEGMENT = /^[^.[\]"\s\p{Cc}]+$/u;
|
|
2
|
+
export function requestCoordinateText(root, segs, label) {
|
|
3
|
+
let out = root;
|
|
4
|
+
for (const seg of segs) {
|
|
5
|
+
if (typeof seg === 'number') {
|
|
6
|
+
out += `[${seg}]`;
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
const shown = label === undefined ? seg : label(seg);
|
|
10
|
+
out += PLAIN_SEGMENT.test(shown) ? `.${shown}` : `[${JSON.stringify(shown)}]`;
|
|
11
|
+
}
|
|
12
|
+
return out;
|
|
13
|
+
}
|