@sema-agent/client-core 0.79.0 → 0.80.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.
@@ -14,3 +14,12 @@ export interface UsageWindowExhaustedDetail {
14
14
  }
15
15
  export declare function usageWindowExhaustedFromError(err: unknown): UsageWindowExhaustedDetail | null;
16
16
  export declare function usageWindowExhaustedContent(detail: UsageWindowExhaustedDetail): string;
17
+ export type DenyAttributionRefusalKind = 'not_in_proof' | 'decision_conflict' | 'attribution_rejected';
18
+ export interface DenyAttributionRefusalDetail {
19
+ kind: DenyAttributionRefusalKind;
20
+ code: string;
21
+ status: number;
22
+ field?: string;
23
+ }
24
+ export declare function denyAttributionRefusalFromError(err: unknown, sentSettledBy: boolean): DenyAttributionRefusalDetail | null;
25
+ export declare function denyAttributionRefusalContent(detail: Pick<DenyAttributionRefusalDetail, 'kind' | 'field'>): string;
@@ -80,3 +80,71 @@ export function usageWindowExhaustedContent(detail) {
80
80
  ? `${head} · Send it again in about ${humanWait(detail.retryAfterSec)}`
81
81
  : `${head} · The engine did not say how long the window needs — send it again a little later`;
82
82
  }
83
+ const SETTLED_BY_NOT_IN_PROOF = 'settled_by_not_in_proof';
84
+ const REQUEST_FIELD_CONFLICT = 'request.field_conflict';
85
+ const RESUME_OUTCOME_INVALID = 'resume_outcome_invalid';
86
+ const APPROVAL_NON_BINDING_FIELDS = new Set(['hostDecision', 'approver']);
87
+ function readRefusalField(o) {
88
+ let extra;
89
+ try {
90
+ extra = o.extra;
91
+ }
92
+ catch {
93
+ extra = undefined;
94
+ }
95
+ if (typeof extra === 'object' && extra !== null && !Array.isArray(extra)) {
96
+ const fromExtra = readStringField(extra, 'field');
97
+ if (fromExtra !== undefined)
98
+ return fromExtra;
99
+ }
100
+ return readStringField(o, 'field');
101
+ }
102
+ export function denyAttributionRefusalFromError(err, sentSettledBy) {
103
+ try {
104
+ if (err === null || typeof err !== 'object')
105
+ return null;
106
+ const o = err;
107
+ const rawStatus = o.status ?? o.statusCode;
108
+ const status = typeof rawStatus === 'number' && Number.isFinite(rawStatus) ? rawStatus : undefined;
109
+ if (status === undefined)
110
+ return null;
111
+ const code = readStringField(o, 'errorCode');
112
+ if (code === undefined)
113
+ return null;
114
+ if (status === 400 && code === SETTLED_BY_NOT_IN_PROOF)
115
+ return { kind: 'not_in_proof', code, status };
116
+ if (status === 400 && code === REQUEST_FIELD_CONFLICT && sentSettledBy) {
117
+ return { kind: 'decision_conflict', code, status };
118
+ }
119
+ if (status === 409 && code === RESUME_OUTCOME_INVALID) {
120
+ const field = readRefusalField(o);
121
+ if (field !== undefined && APPROVAL_NON_BINDING_FIELDS.has(field)) {
122
+ return { kind: 'attribution_rejected', code, status, field };
123
+ }
124
+ }
125
+ return null;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ export function denyAttributionRefusalContent(detail) {
132
+ switch (detail.kind) {
133
+ case 'not_in_proof':
134
+ return ('The engine refused this refusal before judging it: this deployment signs the decisions it accepts, and the note saying ' +
135
+ 'who settled this one is not part of what gets signed · Nothing was decided and the approval is still waiting — ' +
136
+ 'send the same decision again without that note');
137
+ case 'decision_conflict':
138
+ return ('The engine refused this decision before judging it: the body says a policy settled it and also asks to allow the call, ' +
139
+ 'and only a person can allow one · Nothing was decided and the approval is still waiting — ' +
140
+ 'send it again with the decision and the note in agreement');
141
+ case 'attribution_rejected': {
142
+ const named = typeof detail.field === 'string' && APPROVAL_NON_BINDING_FIELDS.has(detail.field)
143
+ ? ` It named ${detail.field} as the part it would not take.`
144
+ : '';
145
+ return ('The engine would not accept the settlement details this decision carried, so it refused the decision before judging it.' +
146
+ `${named} · Nothing was decided and the approval is still waiting at the same coordinates — ` +
147
+ 'check what that part carried (the only piece this client sets is the note saying who settled the refusal) and decide once more');
148
+ }
149
+ }
150
+ }