@sema-agent/core 7.41.1 → 7.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 7.41.2 — 2026-10-05
2
+
3
+ **Hard-breaking changes:** none. **Closed sets:** none added. **Package exports:** +1 / −0 — `steerPriorityOf`. **Behavior narrowing:** none (one reading replaces two; a replay that spelled the default is no longer refused).
4
+
5
+ ### A steer's priority has one reading: absent means `next` (#1361; fix; +1 export) (@server @client-core)
6
+
7
+ - **Before (v7.41.1).** The live acceptance check (`sameAcceptedSteerInput`) compared the admission's normalized priority (`priority ?? "next"`), while the parked replay check (`samePendingSteerPayload`) compared the row's raw member — a row parked without a priority (every row a ≤7.115.0 server parked, or a client that omits the field) against a retry that spelled `"next"` read as a different instruction: `409 steering.duplicate_input_id`, after which a client re-issuing under a fresh id queued the same instruction twice (server S-1121, reproduced on 7.41.1 with `appendPendingSteer`).
8
+ - **Now.** `steerPriorityOf(x)` (src/core/task-notification.ts, the priority word's home; exported) is the one reading — `x.priority ?? "next"` — used by both comparators and by the admission default; `omitted→next`, `next→omitted` and `omitted→omitted` are the idempotent replay (queue unchanged), `next→later` / `next→now` still refuse. Parked rows are written as before (the field stays optional); old rows read through the same default.
9
+ - **Who is hurt.** Nobody: a refusal that was never correct goes away; a real priority change still refuses.
10
+ - **Consumers.** server — S-1121: pin `7.41.2`, flip the probe cell, delete the MIGRATION / contract sentence about this boundary; client-core — none (one export added).
11
+ - Pins: `test/backlog1361-steer-priority-one-reading.test.ts` (A–F from the reproduction; base 7.41.1 red on omitted↔next and on the live check); `test/export-surface.snapshot.json` (+1 name).
12
+
1
13
  ## 7.41.1 — 2026-10-05
2
14
 
3
15
  **Hard-breaking changes:** none. **Closed sets:** none added (two existing sets become reachable from the package root). **Package exports:** +5 / −0 — `SKILL_GRANT_ORIGINS`, `SKILL_ENTRY_INERT_REASONS`, types `SkillGrantOrigin`, `SkillEntryInertReason` (all defined in 7.41.0, re-exported now), and `mintNamespacePrefix` (#1355, defined since the namespace minting landed, re-exported now).
@@ -1,7 +1,7 @@
1
1
  import type { GateOutcome } from "./gate-outcome.js";
2
2
  import { type ExecutionOutcomeRecordWord } from "./checkpoint-execution-record.js";
3
3
  import type { CheckpointPause } from "./pause-registry.js";
4
- import type { SystemInjectionPriority } from "./task-notification.js";
4
+ import { type SystemInjectionPriority } from "./task-notification.js";
5
5
  import { type QuestionAnswer } from "./ask-question.js";
6
6
  import type { ReadEntry } from "../tools/fs/safety.js";
7
7
  import type { RepairBundle } from "../agents/repair-loop.js";
@@ -7,6 +7,7 @@ import { isAskOrigin, isPersistedRuleMandate } from "./ask-origin.js";
7
7
  import { checkpointExecutionRecorded, executionRecordDisposition, ExecutionOutcomeConflictError, } from "./checkpoint-execution-record.js";
8
8
  import { renderUntrustedCommandText, stripFormatCharacters } from "./permission-rule-model.js";
9
9
  import { redactSecrets } from "./untrusted-egress.js";
10
+ import { steerPriorityOf } from "./task-notification.js";
10
11
  import { ASK_USER_QUESTION_TOOL_NAME } from "./ask-question.js";
11
12
  import { isPermissionMode } from "./ask-origin.js";
12
13
  import { wireOf } from "./tool-name-readings.js";
@@ -547,7 +548,7 @@ export function readPendingSteerQueue(state) {
547
548
  function samePendingSteerPayload(a, b) {
548
549
  return (a.text === b.text &&
549
550
  a.trusted === b.trusted &&
550
- a.priority === b.priority &&
551
+ steerPriorityOf(a) === steerPriorityOf(b) &&
551
552
  a.actor?.id === b.actor?.id &&
552
553
  a.actor?.hostAsserted === b.actor?.hostAsserted &&
553
554
  a.actor?.issuer === b.actor?.issuer);
@@ -1,3 +1,4 @@
1
+ import { steerPriorityOf } from "../task-notification.js";
1
2
  const humanInputOrdinals = new WeakMap();
2
3
  export function nextHumanInputSeq(key) {
3
4
  let box = humanInputOrdinals.get(key);
@@ -18,7 +19,7 @@ export function announceAcceptance(record) {
18
19
  export function sameAcceptedSteerInput(a, b) {
19
20
  return (a.payload === b.payload &&
20
21
  a.trusted === b.trusted &&
21
- a.priority === b.priority &&
22
+ steerPriorityOf(a) === steerPriorityOf(b) &&
22
23
  a.actor?.id === b.actor?.id &&
23
24
  a.actor?.hostAsserted === b.actor?.hostAsserted &&
24
25
  a.actor?.issuer === b.actor?.issuer);
@@ -3,7 +3,7 @@ import { snapshotActorAssertion } from "../../internal/llm.js";
3
3
  import { MAX_STEER_INPUT_ID_CHARS } from "../checkpoint-store.js";
4
4
  import { formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
5
5
  import { buildHumanInputEvent, frameMidTurnUserInput, projectHumanInput } from "../human-input-projection.js";
6
- import { isSystemInjectionPriority, SYSTEM_INJECTION_PRIORITIES } from "../task-notification.js";
6
+ import { isSystemInjectionPriority, steerPriorityOf, SYSTEM_INJECTION_PRIORITIES } from "../task-notification.js";
7
7
  import { deliverEngineNotice } from "../types.js";
8
8
  import { inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
9
9
  import { announceAcceptance, armAcceptance, nextHumanInputSeq, sameAcceptedSteerInput } from "./steer-admission.js";
@@ -29,7 +29,7 @@ export function streamSteerVerb(input) {
29
29
  if (priorityIn !== undefined && !isSystemInjectionPriority(priorityIn)) {
30
30
  throw steeringError(`priority must be one of ${SYSTEM_INJECTION_PRIORITIES.join("/")} when supplied`, "steering.invalid_content");
31
31
  }
32
- const priority = priorityIn ?? "next";
32
+ const priority = steerPriorityOf({ priority: priorityIn });
33
33
  const actorIn = options?.actor;
34
34
  const actor = actorIn === undefined ? undefined : snapshotActorAssertion(actorIn);
35
35
  const projected = projectHumanInput({ text, actor, source: "steer" });
@@ -30,6 +30,12 @@ export declare const SYSTEM_INJECTION_PRIORITIES: readonly SystemInjectionPriori
30
30
  * no-subscriber retain path indexes `queues[priority]` and the park path stores it verbatim, so an
31
31
  * unknown value used to travel until something downstream failed on it (or didn't, and lied). */
32
32
  export declare function isSystemInjectionPriority(value: unknown): value is SystemInjectionPriority;
33
+ /** The ONE reading of a steer's priority: a parked row or an accepted input that carries none means `"next"`
34
+ * (the default the live admission has always applied) — so a retry that spells the default and a row parked
35
+ * without it are the same instruction, whichever side normalized. */
36
+ export declare function steerPriorityOf(x: {
37
+ readonly priority?: SystemInjectionPriority;
38
+ }): SystemInjectionPriority;
33
39
  export interface TaskNotificationPayload {
34
40
  task_id: string;
35
41
  /** design/144 §2: `"external"` is CORE-MINTED ONLY — `TaskStream.notify()` casts it onto every
@@ -10,6 +10,9 @@ export const SYSTEM_INJECTION_PRIORITIES = ["now", "next", "later"];
10
10
  export function isSystemInjectionPriority(value) {
11
11
  return typeof value === "string" && SYSTEM_INJECTION_PRIORITIES.includes(value);
12
12
  }
13
+ export function steerPriorityOf(x) {
14
+ return x.priority ?? "next";
15
+ }
13
16
  const TASK_NOTIFICATION_TAGS = [
14
17
  "task-notification",
15
18
  "task-id",
package/dist/index.d.ts CHANGED
@@ -145,7 +145,7 @@ export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS, type RuleToolNameVerdict }
145
145
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
146
146
  export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, type NotificationInjectionOutcome, // the injector's outcome words (`parked_durably` = the session's durable box took the frame)
147
147
  NOTIFICATION_INJECTION_OUTCOMES, // …and their value half + guard, so a host wiring its own uplink validates a reported outcome without duplicating the vocabulary
148
- isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
148
+ isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
149
149
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
150
150
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
151
151
  export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
package/dist/index.js CHANGED
@@ -117,7 +117,7 @@ export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE } from "./co
117
117
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
118
118
  export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS } from "./core/tool-name-aliases.js";
119
119
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
120
- export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
120
+ export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
121
121
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
122
122
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
123
123
  export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.41.1",
3
+ "version": "7.41.2",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a SemVer-BREAKING change; bump MAJOR and update this fixture in the SAME commit (design/87 §4.2 / §5.2). Regenerate via REGEN in test/export-surface.test.ts.",
3
3
  "_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
4
- "count": 2583,
4
+ "count": 2584,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -2515,6 +2515,7 @@
2515
2515
  "splitWorkflowMeta": "function",
2516
2516
  "sqliteQuery": "function",
2517
2517
  "startWorkflow": "function",
2518
+ "steerPriorityOf": "function",
2518
2519
  "storeReadBackShapeContract": "function",
2519
2520
  "stripEngineMetadata": "function",
2520
2521
  "stripFormatCharacters": "function",
@@ -5100,6 +5101,7 @@
5100
5101
  "splitWorkflowMeta": "advanced",
5101
5102
  "sqliteQuery": "advanced",
5102
5103
  "startWorkflow": "advanced",
5104
+ "steerPriorityOf": "advanced",
5103
5105
  "storeReadBackShapeContract": "advanced",
5104
5106
  "stripEngineMetadata": "advanced",
5105
5107
  "stripFormatCharacters": "advanced",
@@ -0,0 +1,54 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.41.2",
4
+ "from": "b8c8666207a044498ac37fb36d14304a66ea5a92",
5
+ "to": "96a0ef21bc1d7887c1016b1762fcb9efaae02252",
6
+ "added": [
7
+ {
8
+ "name": "steerPriorityOf",
9
+ "kind": "function",
10
+ "tier": "advanced",
11
+ "at": [
12
+ "src/core/task-notification.ts:49",
13
+ "src/index.ts:1004"
14
+ ],
15
+ "criteriaCovered": false,
16
+ "breaking": false
17
+ }
18
+ ],
19
+ "removed": [],
20
+ "changed": [],
21
+ "narrowed": [],
22
+ "closedSetMembers": [],
23
+ "closedSetsUnreadable": [],
24
+ "typeKeys": [],
25
+ "typeKeysUnreadableArms": [],
26
+ "typeKeysFlattenedCount": 225,
27
+ "signatures": [],
28
+ "declarationMoves": [],
29
+ "mintMoves": [],
30
+ "criteriaObserves": [
31
+ {
32
+ "kind": "typeMember",
33
+ "name": "PendingSteerEntry.inputId",
34
+ "assertions": [
35
+ "G1.b"
36
+ ]
37
+ },
38
+ {
39
+ "kind": "typeMember",
40
+ "name": "PendingSteerEntry.priority",
41
+ "assertions": [
42
+ "G1.a"
43
+ ]
44
+ }
45
+ ],
46
+ "consumersHint": {
47
+ "cli": [],
48
+ "server": [],
49
+ "sdk": [],
50
+ "note": "scanned cli@e790a1ca server@4160110a sdk@bc45b50 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
51
+ },
52
+ "breakingCount": 0,
53
+ "breakingItems": []
54
+ }