@sema-agent/client-core 0.82.0 → 0.82.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 +33 -0
- package/README.md +10 -7
- package/dist/adapt/toolCards.d.ts +15 -0
- package/dist/adapt/toolCards.js +34 -19
- package/dist/adapter/activeRunSelfHeal.d.ts +3 -0
- package/dist/adapter/activeRunSelfHeal.js +37 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +7 -4
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +44 -5
- package/dist/adapter/runStream.js +33 -4
- package/dist/adapter/types.d.ts +2 -0
- package/dist/agentsWireCaps.d.ts +1 -0
- package/dist/agentsWireCaps.js +110 -29
- package/dist/cloudConfigWireCaps.d.ts +77 -2
- package/dist/cloudConfigWireCaps.js +405 -8
- package/dist/decideFailureNote.d.ts +1 -0
- package/dist/decideFailureNote.js +8 -0
- package/dist/engineNoticeCodes.js +2 -0
- package/dist/executionLaneCapability.js +3 -0
- package/dist/fileHistoryCaptureCapability.d.ts +18 -0
- package/dist/fileHistoryCaptureCapability.js +58 -0
- package/dist/gateOutcome.js +2 -0
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +1 -1
- package/dist/hitl/frameRouter.d.ts +2 -1
- package/dist/hitl/hitlBridge.d.ts +29 -1
- package/dist/hitl/hitlBridge.js +135 -3
- package/dist/hitl/hitlHostSurface.js +2 -3
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +17 -9
- package/dist/hitl/planReviewWire.d.ts +6 -0
- package/dist/hitl/planReviewWire.js +8 -2
- package/dist/hitl/toolApprovalWire.d.ts +2 -1
- package/dist/hitl/toolApprovalWire.js +105 -102
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/modelIdentityResolvability.d.ts +31 -0
- package/dist/modelIdentityResolvability.js +145 -0
- package/dist/notifications.d.ts +3 -1
- package/dist/notifications.js +18 -2
- package/dist/printToolResultFrame.js +15 -1
- package/dist/resumeRefusalCopy.d.ts +12 -0
- package/dist/resumeRefusalCopy.js +45 -1
- package/dist/seam.d.ts +2 -0
- package/dist/toolResult.d.ts +2 -2
- package/dist/toolResult.js +7 -6
- package/docs/INTEGRATION-CLIENTS.md +168 -11
- package/package.json +3 -3
|
@@ -36,9 +36,10 @@ export const INTERNAL_SDK_ARM_TYPES = new Set([
|
|
|
36
36
|
'approval_revoke',
|
|
37
37
|
'message_committed',
|
|
38
38
|
]);
|
|
39
|
-
function assistantArm(ctx, content, eventId) {
|
|
39
|
+
function assistantArm(ctx, content, eventId, parentToolCallId) {
|
|
40
40
|
const id = typeof eventId === 'string' && eventId.length > 0 ? eventId : undefined;
|
|
41
|
-
const
|
|
41
|
+
const parent = typeof parentToolCallId === 'string' && parentToolCallId.length > 0 ? parentToolCallId : undefined;
|
|
42
|
+
const model = parent === undefined && typeof ctx.model === 'string' && ctx.model.length > 0 ? ctx.model : undefined;
|
|
42
43
|
return stamp(ctx, armBody({
|
|
43
44
|
type: 'assistant',
|
|
44
45
|
message: {
|
|
@@ -47,7 +48,7 @@ function assistantArm(ctx, content, eventId) {
|
|
|
47
48
|
...(id !== undefined ? { id } : {}),
|
|
48
49
|
...(model !== undefined ? { model } : {}),
|
|
49
50
|
},
|
|
50
|
-
parent_tool_use_id: null,
|
|
51
|
+
parent_tool_use_id: parent ?? null,
|
|
51
52
|
}));
|
|
52
53
|
}
|
|
53
54
|
function streamEventArm(ctx, event) {
|
|
@@ -136,7 +137,7 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
136
137
|
? { parentToolCallId: ev.parentToolCallId }
|
|
137
138
|
: {}),
|
|
138
139
|
},
|
|
139
|
-
], ev.eventId));
|
|
140
|
+
], ev.eventId, ev.parentToolCallId));
|
|
140
141
|
case 'compacted': {
|
|
141
142
|
const raw = ev;
|
|
142
143
|
const freedTokens = typeof raw.freedTokens === 'number' && Number.isFinite(raw.freedTokens) && raw.freedTokens >= 0 ? raw.freedTokens : undefined;
|
|
@@ -171,6 +172,7 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
171
172
|
const toolEndGatedCallId = ev.gatedCallId;
|
|
172
173
|
const collateralAbort = ev._sema_collateral_abort;
|
|
173
174
|
const denialKind = ccToolDenialKindForToolEnd(ev);
|
|
175
|
+
const denialUnclassified = denialKind === undefined && toolEndGate?.disposition.kind === 'denied';
|
|
174
176
|
return projected(stamp(ctx, armBody({
|
|
175
177
|
type: 'tool_end_result',
|
|
176
178
|
toolCallId: ev.toolCallId,
|
|
@@ -192,6 +194,7 @@ export function eventToSdkMessage(ev, ctx) {
|
|
|
192
194
|
: {}),
|
|
193
195
|
...(collateralAbort === true ? { _sema_collateral_abort: true } : {}),
|
|
194
196
|
...(denialKind !== undefined ? { _sema_denial_kind: denialKind } : {}),
|
|
197
|
+
...(denialUnclassified ? { _sema_denial_unclassified: true } : {}),
|
|
195
198
|
...(ev.eventId !== undefined ? { eventId: ev.eventId } : {}),
|
|
196
199
|
...(ev.parentToolCallId !== undefined
|
|
197
200
|
? { parentToolCallId: ev.parentToolCallId }
|
|
@@ -20,6 +20,8 @@ export interface TerminalStreamObserved {
|
|
|
20
20
|
readonly denialKindByCallId?: ReadonlyMap<string, string>;
|
|
21
21
|
readonly successfulToolEndObserved?: boolean;
|
|
22
22
|
readonly streamSawRunOpen?: boolean;
|
|
23
|
+
readonly deniedToolNameByCallId?: ReadonlyMap<string, string | undefined>;
|
|
24
|
+
readonly deniedCallsOverflowed?: boolean;
|
|
23
25
|
}
|
|
24
26
|
export declare const TOOL_INPUT_JOIN_MAX_CALLS = 4096;
|
|
25
27
|
export interface SemaPermissionDenial {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCcToolDenialKind, isGateDeniedByWord } from '../../gateVocabulary.js';
|
|
1
|
+
import { isCcToolDenialKind, isCcToolDenialKindADenial, isGateDeniedByWord } from '../../gateVocabulary.js';
|
|
2
2
|
import { stamp } from '../types.js';
|
|
3
3
|
import { putOwnKey } from '../../ownKey.js';
|
|
4
4
|
import { readEffectiveReasoning, readEffectiveMemoryScopes } from '../../effectiveFacts.js';
|
|
@@ -65,11 +65,10 @@ function permissionDenialParts(stats, observed) {
|
|
|
65
65
|
const gateDeniedByByCallId = observed?.gateDeniedByByCallId;
|
|
66
66
|
const denialKindByCallId = observed?.denialKindByCallId;
|
|
67
67
|
const hr = stats?.humanReview;
|
|
68
|
-
const
|
|
69
|
-
if (!Array.isArray(gates))
|
|
70
|
-
return { permission_denials: [], _sema_permission_denials_absent: true };
|
|
68
|
+
const gatesRaw = hr !== null && typeof hr === 'object' ? hr.gates : undefined;
|
|
71
69
|
const denials = [];
|
|
72
|
-
|
|
70
|
+
const gates = Array.isArray(gatesRaw) ? gatesRaw : [];
|
|
71
|
+
let complete = Array.isArray(gatesRaw);
|
|
73
72
|
for (const g of gates) {
|
|
74
73
|
if (g === null || typeof g !== 'object') {
|
|
75
74
|
complete = false;
|
|
@@ -125,6 +124,43 @@ function permissionDenialParts(stats, observed) {
|
|
|
125
124
|
...(toolArg !== undefined ? { _sema_tool_arg: toolArg } : {}),
|
|
126
125
|
});
|
|
127
126
|
}
|
|
127
|
+
const deniedToolNameByCallId = observed?.deniedToolNameByCallId;
|
|
128
|
+
if (deniedToolNameByCallId !== undefined) {
|
|
129
|
+
const ledgerDeniedIds = new Set();
|
|
130
|
+
let ledgerHasIdlessDenial = false;
|
|
131
|
+
for (const d of denials) {
|
|
132
|
+
if (d.tool_use_id !== undefined)
|
|
133
|
+
ledgerDeniedIds.add(d.tool_use_id);
|
|
134
|
+
else
|
|
135
|
+
ledgerHasIdlessDenial = true;
|
|
136
|
+
}
|
|
137
|
+
for (const [callId, toolNameRaw] of deniedToolNameByCallId) {
|
|
138
|
+
if (typeof callId !== 'string' || callId.length === 0 || ledgerDeniedIds.has(callId))
|
|
139
|
+
continue;
|
|
140
|
+
const mergedKind = denialKindByCallId?.has(callId) === true ? denialKindByCallId.get(callId) : undefined;
|
|
141
|
+
if (isCcToolDenialKind(mergedKind) && !isCcToolDenialKindADenial(mergedKind))
|
|
142
|
+
continue;
|
|
143
|
+
if (ledgerHasIdlessDenial) {
|
|
144
|
+
complete = false;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const toolName = nonEmptyStr(toolNameRaw);
|
|
148
|
+
const joinedInput = toolInputByCallId?.has(callId) === true ? joinableToolInput(toolInputByCallId.get(callId)) : undefined;
|
|
149
|
+
const deniedByRaw = gateDeniedByByCallId?.has(callId) === true ? gateDeniedByByCallId.get(callId) : undefined;
|
|
150
|
+
const deniedBy = typeof deniedByRaw === 'string' && isGateDeniedByWord(deniedByRaw) ? deniedByRaw : undefined;
|
|
151
|
+
const toolDenialKind = isCcToolDenialKind(mergedKind) ? mergedKind : undefined;
|
|
152
|
+
denials.push({
|
|
153
|
+
...(toolName !== undefined ? { tool_name: toolName } : {}),
|
|
154
|
+
tool_use_id: callId,
|
|
155
|
+
...(joinedInput !== undefined ? { tool_input: joinedInput, _sema_tool_input_source: 'tool_start' } : {}),
|
|
156
|
+
...(deniedBy !== undefined ? { deniedBy, _sema_denied_by_source: 'tool_end' } : {}),
|
|
157
|
+
...(toolDenialKind !== undefined ? { toolDenialKind } : {}),
|
|
158
|
+
});
|
|
159
|
+
ledgerDeniedIds.add(callId);
|
|
160
|
+
}
|
|
161
|
+
if (observed?.deniedCallsOverflowed === true)
|
|
162
|
+
complete = false;
|
|
163
|
+
}
|
|
128
164
|
const ccList = denials.filter((d) => d.tool_name !== undefined && d.tool_use_id !== undefined && d.tool_input !== undefined);
|
|
129
165
|
const claimable = complete && ccList.length === denials.length;
|
|
130
166
|
const zeroOutputDenied = denials.length > 0 && observed?.streamSawRunOpen === true && observed.successfulToolEndObserved === false;
|
|
@@ -200,15 +236,18 @@ function structuredOutputParts(r) {
|
|
|
200
236
|
function effectiveFactParts(rec) {
|
|
201
237
|
const reasoning = readEffectiveReasoning(rec.effectiveReasoning);
|
|
202
238
|
const scopes = readEffectiveMemoryScopes(rec.effectiveMemoryScopes);
|
|
239
|
+
const responseModel = rec.responseModel;
|
|
203
240
|
return {
|
|
204
241
|
...(reasoning !== undefined ? { _sema_effective_reasoning: reasoning } : {}),
|
|
205
242
|
...(scopes !== undefined ? { _sema_effective_memory_scopes: scopes } : {}),
|
|
243
|
+
...(typeof responseModel === 'string' && responseModel.length > 0 ? { _sema_response_model: responseModel } : {}),
|
|
206
244
|
};
|
|
207
245
|
}
|
|
208
246
|
function reemitEffectiveFacts(f) {
|
|
209
247
|
const out = {
|
|
210
248
|
...(f?._sema_effective_reasoning !== undefined ? { _sema_effective_reasoning: f._sema_effective_reasoning } : {}),
|
|
211
249
|
...(f?._sema_effective_memory_scopes !== undefined ? { _sema_effective_memory_scopes: f._sema_effective_memory_scopes } : {}),
|
|
250
|
+
...(f?._sema_response_model !== undefined ? { _sema_response_model: f._sema_response_model } : {}),
|
|
212
251
|
};
|
|
213
252
|
const _keySetPin = true;
|
|
214
253
|
void _keySetPin;
|
|
@@ -6,7 +6,7 @@ import { coerceOutput, publishSubagentContentEvent } from '../subagentContentSto
|
|
|
6
6
|
import { ACTIVE_RUN_BUSY_ERROR_CODE, OUTPUT_INVALID, isLimitsExceededCode } from '../engineErrorCodes.js';
|
|
7
7
|
import { isReviewPark, readRunTerminal, runTerminalCode } from '../runTerminal.js';
|
|
8
8
|
import { ccToolDenialKindForToolEnd, gateDeniedBy, gateOutcomeOf } from '../gateOutcome.js';
|
|
9
|
-
import { isCcToolDenialKind, isGateDeniedByWord } from '../gateVocabulary.js';
|
|
9
|
+
import { isCcToolDenialKind, isCcToolDenialKindADenial, isGateDeniedByWord } from '../gateVocabulary.js';
|
|
10
10
|
const mainLane = () => ({ lane: 'main' });
|
|
11
11
|
function emitChromeFireAndForget(ctx, event) {
|
|
12
12
|
try {
|
|
@@ -185,6 +185,8 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
185
185
|
const denialKindSourceByCallId = new Map();
|
|
186
186
|
const denialAmbiguous = new Set();
|
|
187
187
|
let denialJoinOverflowed = false;
|
|
188
|
+
const deniedToolNameByCallId = new Map();
|
|
189
|
+
let deniedCallsOverflowed = false;
|
|
188
190
|
let successfulToolEndObserved = false;
|
|
189
191
|
let streamSawRunOpen = false;
|
|
190
192
|
const sameArgs = (a, b) => {
|
|
@@ -229,7 +231,8 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
229
231
|
if (ev.type === 'tool_end') {
|
|
230
232
|
const endCallId = ev.toolCallId;
|
|
231
233
|
if (typeof endCallId === 'string' && endCallId.length > 0) {
|
|
232
|
-
const
|
|
234
|
+
const endGate = gateOutcomeOf(ev);
|
|
235
|
+
const deniedByRaw = gateDeniedBy(endGate);
|
|
233
236
|
const deniedBy = isGateDeniedByWord(deniedByRaw) ? deniedByRaw : undefined;
|
|
234
237
|
const kind = ccToolDenialKindForToolEnd(ev);
|
|
235
238
|
const kindSource = kind === undefined
|
|
@@ -237,6 +240,23 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
237
240
|
: isCcToolDenialKind(ev._sema_denial_kind)
|
|
238
241
|
? 'local'
|
|
239
242
|
: 'wire';
|
|
243
|
+
const deniedCall = endGate !== undefined
|
|
244
|
+
? endGate.disposition.kind === 'denied' && (kind === undefined || isCcToolDenialKindADenial(kind))
|
|
245
|
+
: kind !== undefined && isCcToolDenialKindADenial(kind);
|
|
246
|
+
if (deniedCall) {
|
|
247
|
+
const endToolNameRaw = ev.toolName;
|
|
248
|
+
const endToolName = typeof endToolNameRaw === 'string' && endToolNameRaw.length > 0 ? endToolNameRaw : undefined;
|
|
249
|
+
if (deniedToolNameByCallId.has(endCallId)) {
|
|
250
|
+
if (deniedToolNameByCallId.get(endCallId) !== endToolName)
|
|
251
|
+
deniedToolNameByCallId.set(endCallId, undefined);
|
|
252
|
+
}
|
|
253
|
+
else if (deniedToolNameByCallId.size >= TOOL_INPUT_JOIN_MAX_CALLS) {
|
|
254
|
+
deniedCallsOverflowed = true;
|
|
255
|
+
}
|
|
256
|
+
else if (!deniedCallsOverflowed) {
|
|
257
|
+
deniedToolNameByCallId.set(endCallId, endToolName);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
240
260
|
if (deniedBy !== undefined || kind !== undefined) {
|
|
241
261
|
const isNew = (deniedBy !== undefined && !gateDeniedByByCallId.has(endCallId)) ||
|
|
242
262
|
(kind !== undefined && !denialKindByCallId.has(endCallId));
|
|
@@ -298,14 +318,18 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
298
318
|
output: coerceOutput(sub.output),
|
|
299
319
|
isError: sub.isError,
|
|
300
320
|
});
|
|
301
|
-
|
|
321
|
+
if (!(ctx.lane === 'print' && (sub.type === 'tool_start' || sub.type === 'tool_end')))
|
|
322
|
+
continue;
|
|
302
323
|
}
|
|
303
324
|
if (ev.type === 'turn_end') {
|
|
304
325
|
const usageMissing = ev.usageMissing === true;
|
|
305
326
|
if (usageMissing)
|
|
306
327
|
usageMissingObserved = true;
|
|
307
|
-
const
|
|
328
|
+
const turnEndLoose = ev;
|
|
329
|
+
const stopReasonRaw = turnEndLoose.stopReason;
|
|
308
330
|
const stopWord = typeof stopReasonRaw === 'string' && stopReasonRaw.length > 0 ? stopReasonRaw : undefined;
|
|
331
|
+
const responseModelRaw = turnEndLoose.responseModel;
|
|
332
|
+
const responseModelWord = typeof responseModelRaw === 'string' && responseModelRaw.length > 0 ? responseModelRaw : undefined;
|
|
309
333
|
const rawUsage = ev.usage;
|
|
310
334
|
const engineUsage = typeof rawUsage === 'object' && rawUsage !== null && !Array.isArray(rawUsage)
|
|
311
335
|
? rawUsage
|
|
@@ -340,6 +364,7 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
340
364
|
engineUsage,
|
|
341
365
|
...(usageMissing ? { usageMissing: true } : {}),
|
|
342
366
|
...(stopWord !== undefined ? { stopReason: stopWord } : {}),
|
|
367
|
+
...(responseModelWord !== undefined ? { responseModel: responseModelWord } : {}),
|
|
343
368
|
});
|
|
344
369
|
}
|
|
345
370
|
}
|
|
@@ -362,6 +387,7 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
362
387
|
engineUsage,
|
|
363
388
|
...(usageMissing ? { usageMissing: true } : {}),
|
|
364
389
|
...(stopWord !== undefined ? { stopReason: stopWord } : {}),
|
|
390
|
+
...(responseModelWord !== undefined ? { responseModel: responseModelWord } : {}),
|
|
365
391
|
});
|
|
366
392
|
}
|
|
367
393
|
const rowKey = sourceTaskId !== undefined ? `s:${sourceTaskId}` : `p:${taskId}`;
|
|
@@ -389,6 +415,7 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
389
415
|
? { outputTokens }
|
|
390
416
|
: {}),
|
|
391
417
|
...(stopWord !== undefined ? { _sema_stop_reason: stopWord } : {}),
|
|
418
|
+
...(responseModelWord !== undefined ? { _sema_response_model: responseModelWord } : {}),
|
|
392
419
|
};
|
|
393
420
|
}
|
|
394
421
|
continue;
|
|
@@ -453,6 +480,8 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
453
480
|
denialKindByCallId,
|
|
454
481
|
successfulToolEndObserved,
|
|
455
482
|
streamSawRunOpen,
|
|
483
|
+
deniedToolNameByCallId,
|
|
484
|
+
deniedCallsOverflowed,
|
|
456
485
|
});
|
|
457
486
|
const outcome = resultFrame.
|
|
458
487
|
_sema_outcome;
|
package/dist/adapter/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentEvent } from '@sema-agent/sdk';
|
|
2
2
|
import type { ModelUsage, SDKMessage } from '@sema-agent/agent-types';
|
|
3
3
|
import type { ChromeEvent } from '../seam.js';
|
|
4
|
+
import type { RequestLane } from '../request/taskRequest.js';
|
|
4
5
|
export type { ModelUsage, SDKMessage };
|
|
5
6
|
export type StampedAgentEvent = AgentEvent & {
|
|
6
7
|
id?: string;
|
|
@@ -16,6 +17,7 @@ export interface EmitContext {
|
|
|
16
17
|
sessionId: string;
|
|
17
18
|
startedAtMs?: number;
|
|
18
19
|
model?: string;
|
|
20
|
+
lane?: RequestLane;
|
|
19
21
|
emitChrome?(event: ChromeEvent): void | Promise<void>;
|
|
20
22
|
onDroppedFrame?(info: DroppedFrameInfo): void;
|
|
21
23
|
}
|
package/dist/agentsWireCaps.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export type WireConfig = {
|
|
|
69
69
|
};
|
|
70
70
|
export type ProjectorFn = () => Promise<ProjectAgentsResult>;
|
|
71
71
|
export declare function prepareTaskAgentsWireWith(cfg: WireConfig, projector: ProjectorFn): Promise<void>;
|
|
72
|
+
export declare function invalidateTaskAgentsWire(): Promise<void>;
|
|
72
73
|
export declare function awaitTaskAgentsWire(timeoutMs?: number): Promise<void>;
|
|
73
74
|
export declare function taskAgentsField(): {
|
|
74
75
|
agents?: TaskAgentWireItem[];
|
package/dist/agentsWireCaps.js
CHANGED
|
@@ -194,6 +194,7 @@ let preparedKey = null;
|
|
|
194
194
|
let preparedPromise = null;
|
|
195
195
|
let payload;
|
|
196
196
|
let capsVerdict;
|
|
197
|
+
let settleGeneration = null;
|
|
197
198
|
const emittedWarnings = new Set();
|
|
198
199
|
function warnOnce(msg) {
|
|
199
200
|
if (emittedWarnings.has(msg))
|
|
@@ -201,30 +202,57 @@ function warnOnce(msg) {
|
|
|
201
202
|
emittedWarnings.add(msg);
|
|
202
203
|
console.error(`[sema] ${msg}`);
|
|
203
204
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
principal: cfg.principal,
|
|
210
|
-
}),
|
|
211
|
-
projector(),
|
|
212
|
-
]);
|
|
213
|
-
capsVerdict = caps;
|
|
214
|
-
if (projected.agents && caps === false) {
|
|
215
|
-
warnOnce(`agents wire: this engine does not support per-task custom agents (capabilities.taskAgents absent/false — server <1.205 or multi-tenant) — ${projected.agents.length} custom agent definition(s) will NOT be sent`);
|
|
216
|
-
payload = undefined;
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
205
|
+
function applyProjectionIfCurrent(generation, projected) {
|
|
206
|
+
if (generation === null || preparedPromise !== generation)
|
|
207
|
+
return false;
|
|
208
|
+
const accepted = capsVerdict !== false;
|
|
209
|
+
if (accepted) {
|
|
219
210
|
for (const w of projected.warnings)
|
|
220
211
|
warnOnce(w);
|
|
221
212
|
payload = projected.agents;
|
|
213
|
+
}
|
|
214
|
+
settleGeneration?.();
|
|
215
|
+
return accepted;
|
|
216
|
+
}
|
|
217
|
+
function startCapsProbe(cfg) {
|
|
218
|
+
const land = (verdict) => {
|
|
219
|
+
if (capsVerdict !== probe)
|
|
220
|
+
return verdict;
|
|
221
|
+
capsVerdict = verdict;
|
|
222
|
+
if (verdict === false) {
|
|
223
|
+
payload = undefined;
|
|
224
|
+
settleGeneration?.();
|
|
225
|
+
}
|
|
226
|
+
return verdict;
|
|
227
|
+
};
|
|
228
|
+
const probe = engineSupportsTaskAgents(cfg.baseUrl, {
|
|
229
|
+
authToken: cfg.authToken,
|
|
230
|
+
principal: cfg.principal,
|
|
231
|
+
}).then(land, () => land(undefined));
|
|
232
|
+
capsVerdict = probe;
|
|
233
|
+
return probe;
|
|
234
|
+
}
|
|
235
|
+
function capsSettled() {
|
|
236
|
+
return capsVerdict instanceof Promise ? capsVerdict : Promise.resolve();
|
|
237
|
+
}
|
|
238
|
+
async function runPrepare(cfg, projector, probe, generation) {
|
|
239
|
+
try {
|
|
240
|
+
const [caps, projected] = await Promise.all([probe, projector()]);
|
|
241
|
+
if (caps === false) {
|
|
242
|
+
if (projected.agents && preparedKey === cfg.baseUrl) {
|
|
243
|
+
warnOnce(`agents wire: this engine does not support per-task custom agents (capabilities.taskAgents absent/false — server <1.205 or multi-tenant) — ${projected.agents.length} custom agent definition(s) will NOT be sent`);
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (!applyProjectionIfCurrent(generation, projected))
|
|
248
|
+
return;
|
|
222
249
|
if (payload && hostEnv().SEMA_DEBUG) {
|
|
223
250
|
console.error(`[sema] agents wire: ${payload.length} custom agent(s) → TaskRequest.agents (${payload.map(a => a.name).join(', ')})`);
|
|
224
251
|
}
|
|
225
252
|
}
|
|
226
253
|
catch (e) {
|
|
227
|
-
|
|
254
|
+
if (preparedPromise === generation)
|
|
255
|
+
payload = undefined;
|
|
228
256
|
if (hostEnv().SEMA_DEBUG) {
|
|
229
257
|
console.error('[sema] agents wire prepare soft-failed (no agents stamped):', e);
|
|
230
258
|
}
|
|
@@ -235,21 +263,66 @@ export function prepareTaskAgentsWireWith(cfg, projector) {
|
|
|
235
263
|
if (preparedPromise && preparedKey === key)
|
|
236
264
|
return preparedPromise;
|
|
237
265
|
preparedKey = key;
|
|
238
|
-
preparedPromise = runPrepare(cfg, projector);
|
|
239
266
|
activeProjector = projector;
|
|
240
|
-
|
|
267
|
+
const probe = startCapsProbe(cfg);
|
|
268
|
+
return startGeneration(generation => runPrepare(cfg, projector, probe, generation));
|
|
269
|
+
}
|
|
270
|
+
function startGeneration(run) {
|
|
271
|
+
let settle;
|
|
272
|
+
const generation = new Promise(resolve => {
|
|
273
|
+
settle = resolve;
|
|
274
|
+
});
|
|
275
|
+
const superseded = settleGeneration;
|
|
276
|
+
preparedPromise = generation;
|
|
277
|
+
settleGeneration = settle;
|
|
278
|
+
superseded?.();
|
|
279
|
+
void run(generation).then(settle, settle);
|
|
280
|
+
return generation;
|
|
281
|
+
}
|
|
282
|
+
export function invalidateTaskAgentsWire() {
|
|
283
|
+
const projector = activeProjector;
|
|
284
|
+
if (!preparedPromise || !projector)
|
|
285
|
+
return Promise.resolve();
|
|
286
|
+
payload = undefined;
|
|
287
|
+
return startGeneration(generation => runReproject(projector, generation));
|
|
288
|
+
}
|
|
289
|
+
async function runReproject(projector, generation) {
|
|
290
|
+
try {
|
|
291
|
+
let projected;
|
|
292
|
+
try {
|
|
293
|
+
projected = await projector();
|
|
294
|
+
}
|
|
295
|
+
catch (e) {
|
|
296
|
+
if (hostEnv().SEMA_DEBUG) {
|
|
297
|
+
console.error('[sema] agents wire re-project soft-failed (no agents stamped until the next successful projection):', e);
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await capsSettled();
|
|
302
|
+
applyProjectionIfCurrent(generation, projected);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
}
|
|
241
306
|
}
|
|
242
307
|
export async function awaitTaskAgentsWire(timeoutMs = 4000) {
|
|
243
308
|
if (!preparedPromise)
|
|
244
309
|
return;
|
|
310
|
+
if (capsVerdict === false)
|
|
311
|
+
return;
|
|
245
312
|
let timeoutHandle;
|
|
313
|
+
let timedOut = false;
|
|
314
|
+
const deadline = new Promise(resolve => {
|
|
315
|
+
timeoutHandle = setTimeout(() => {
|
|
316
|
+
timedOut = true;
|
|
317
|
+
resolve();
|
|
318
|
+
}, timeoutMs);
|
|
319
|
+
});
|
|
246
320
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
]);
|
|
321
|
+
let waited = null;
|
|
322
|
+
while (!timedOut && preparedPromise !== null && preparedPromise !== waited) {
|
|
323
|
+
waited = preparedPromise;
|
|
324
|
+
await Promise.race([waited.catch(() => { }), deadline]);
|
|
325
|
+
}
|
|
253
326
|
}
|
|
254
327
|
finally {
|
|
255
328
|
if (timeoutHandle !== undefined)
|
|
@@ -259,11 +332,18 @@ export async function awaitTaskAgentsWire(timeoutMs = 4000) {
|
|
|
259
332
|
export function taskAgentsField() {
|
|
260
333
|
const current = payload;
|
|
261
334
|
if (preparedPromise && capsVerdict !== false && activeProjector) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
335
|
+
const generation = preparedPromise;
|
|
336
|
+
let refreshing;
|
|
337
|
+
try {
|
|
338
|
+
refreshing = activeProjector();
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return current ? { agents: current } : {};
|
|
342
|
+
}
|
|
343
|
+
void refreshing
|
|
344
|
+
.then(async (p) => {
|
|
345
|
+
await capsSettled();
|
|
346
|
+
applyProjectionIfCurrent(generation, p);
|
|
267
347
|
})
|
|
268
348
|
.catch(() => { });
|
|
269
349
|
}
|
|
@@ -273,6 +353,7 @@ export function _resetAgentsWireForTest() {
|
|
|
273
353
|
activeProjector = null;
|
|
274
354
|
preparedKey = null;
|
|
275
355
|
preparedPromise = null;
|
|
356
|
+
settleGeneration = null;
|
|
276
357
|
payload = undefined;
|
|
277
358
|
capsVerdict = undefined;
|
|
278
359
|
emittedWarnings.clear();
|
|
@@ -16,7 +16,17 @@ export interface CloudMcpProjection {
|
|
|
16
16
|
}
|
|
17
17
|
export declare function cloudMcpToSpecs(servers: unknown, env: EnvLike): CloudMcpProjection;
|
|
18
18
|
export declare function cloudSkillsToSpecs(manifestSkills: unknown, resolveBody: (contentHash: string) => string | null): SkillSpec[];
|
|
19
|
-
export
|
|
19
|
+
export interface CloudModelRefIssue {
|
|
20
|
+
readonly key: 'models' | 'default' | 'roles' | 'atModelAllowlist' | 'tierGroups' | 'activeTierGroup';
|
|
21
|
+
readonly at?: string;
|
|
22
|
+
readonly target?: string;
|
|
23
|
+
readonly reason: 'dangling' | 'rejected' | 'unreadable' | 'unsupported' | 'duplicate';
|
|
24
|
+
readonly outcome: 'dropped' | 'kept';
|
|
25
|
+
}
|
|
26
|
+
export interface CloudModelsDocOptions {
|
|
27
|
+
readonly entryAccepted?: (entry: object) => boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function cloudModelsToDoc(models: unknown, opts?: CloudModelsDocOptions): Rec | null;
|
|
20
30
|
export interface CloudDroppedModel {
|
|
21
31
|
id?: string;
|
|
22
32
|
name?: string;
|
|
@@ -35,6 +45,62 @@ export interface CloudExecutionProjection {
|
|
|
35
45
|
}
|
|
36
46
|
export declare function cloudExecutionToPolicy(execution: unknown): CloudExecutionProjection;
|
|
37
47
|
export declare function cloudRosterNames(rostersValue: unknown): string[];
|
|
48
|
+
export interface CloudEffectiveWarning {
|
|
49
|
+
readonly kind: string;
|
|
50
|
+
readonly domain?: string;
|
|
51
|
+
readonly droppedNames?: readonly string[];
|
|
52
|
+
readonly keys?: readonly string[];
|
|
53
|
+
readonly path?: string;
|
|
54
|
+
readonly file?: string;
|
|
55
|
+
readonly why?: string;
|
|
56
|
+
readonly truncatedFrom?: number;
|
|
57
|
+
}
|
|
58
|
+
export type CloudEffectiveWarningsReading = {
|
|
59
|
+
readonly kind: 'reported';
|
|
60
|
+
readonly warnings: readonly CloudEffectiveWarning[];
|
|
61
|
+
readonly unreadable: number;
|
|
62
|
+
} | {
|
|
63
|
+
readonly kind: 'unknown';
|
|
64
|
+
};
|
|
65
|
+
export interface CloudBudgetModelLimits {
|
|
66
|
+
readonly maxBudgetUsd?: number;
|
|
67
|
+
readonly tpmLimit?: number;
|
|
68
|
+
readonly rpmLimit?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface CloudBudgetLimits {
|
|
71
|
+
readonly mode?: string;
|
|
72
|
+
readonly maxBudgetUsd?: number;
|
|
73
|
+
readonly budgetDuration?: string;
|
|
74
|
+
readonly tpmLimit?: number;
|
|
75
|
+
readonly rpmLimit?: number;
|
|
76
|
+
readonly maxParallelRequests?: number;
|
|
77
|
+
readonly perModel?: Readonly<Record<string, CloudBudgetModelLimits>>;
|
|
78
|
+
readonly maxRunCostUsd?: number;
|
|
79
|
+
readonly maxIterations?: number;
|
|
80
|
+
readonly enforcement?: string;
|
|
81
|
+
}
|
|
82
|
+
export type CloudBudgetReading = {
|
|
83
|
+
readonly kind: 'configured';
|
|
84
|
+
readonly limits: CloudBudgetLimits;
|
|
85
|
+
readonly uninterpretedKeys: readonly string[];
|
|
86
|
+
} | {
|
|
87
|
+
readonly kind: 'not-configured';
|
|
88
|
+
} | {
|
|
89
|
+
readonly kind: 'redacted';
|
|
90
|
+
} | {
|
|
91
|
+
readonly kind: 'unknown';
|
|
92
|
+
};
|
|
93
|
+
export type CloudRuntimeCapsReading = {
|
|
94
|
+
readonly kind: 'configured';
|
|
95
|
+
readonly caps: Readonly<Record<string, boolean>>;
|
|
96
|
+
readonly uninterpretedKeys: readonly string[];
|
|
97
|
+
} | {
|
|
98
|
+
readonly kind: 'not-configured';
|
|
99
|
+
} | {
|
|
100
|
+
readonly kind: 'redacted';
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: 'unknown';
|
|
103
|
+
};
|
|
38
104
|
export interface CloudProjection {
|
|
39
105
|
mcp: McpServerSpec[];
|
|
40
106
|
skills: SkillSpec[];
|
|
@@ -47,5 +113,14 @@ export interface CloudProjection {
|
|
|
47
113
|
droppedMcpServers: CloudMcpDroppedServer[];
|
|
48
114
|
droppedModels: CloudDroppedModel[];
|
|
49
115
|
execution: CloudExecutionProjection;
|
|
116
|
+
effectiveWarnings: CloudEffectiveWarningsReading;
|
|
117
|
+
budget: CloudBudgetReading;
|
|
118
|
+
runtimeCaps: CloudRuntimeCapsReading;
|
|
119
|
+
modelRefIssues: CloudModelRefIssue[];
|
|
120
|
+
}
|
|
121
|
+
export declare function projectEffectiveBody(body: unknown, skillBodies: Record<string, string>, env: EnvLike, rostersValue?: unknown, opts?: CloudModelsDocOptions): CloudProjection;
|
|
122
|
+
export interface CloudEffectiveNotice {
|
|
123
|
+
readonly level: 'warn' | 'info';
|
|
124
|
+
readonly text: string;
|
|
50
125
|
}
|
|
51
|
-
export declare function
|
|
126
|
+
export declare function cloudEffectiveNotices(p: Pick<CloudProjection, 'effectiveWarnings' | 'budget' | 'runtimeCaps' | 'modelRefIssues'>): CloudEffectiveNotice[];
|