@sema-agent/client-core 0.84.0 → 0.85.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 +247 -0
- package/README.md +27 -13
- package/dist/abortableSleep.d.ts +10 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +1 -1
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +1 -1
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +1 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +19 -10
- package/dist/adapter/runStream.js +6 -2
- package/dist/agentSession/engineSessionBackgroundStop.d.ts +50 -0
- package/dist/agentSession/engineSessionBackgroundStop.js +291 -0
- package/dist/agentsWireCaps.d.ts +2 -1
- package/dist/agentsWireCaps.js +8 -0
- package/dist/cloudConfigWireCaps.js +2 -1
- package/dist/corruptSession.d.ts +3 -0
- package/dist/corruptSession.js +29 -0
- package/dist/corruptSessionCopy.d.ts +1 -0
- package/dist/corruptSessionCopy.js +4 -0
- package/dist/decideFailureNote.d.ts +2 -1
- package/dist/decideFailureNote.js +8 -3
- package/dist/decideReceipt.d.ts +6 -0
- package/dist/decideReceipt.js +30 -1
- package/dist/detachWire.d.ts +1 -0
- package/dist/detachWire.js +13 -5
- package/dist/displayUntrusted.js +114 -18
- package/dist/effortWire.d.ts +2 -1
- package/dist/effortWire.js +2 -4
- package/dist/engineErrorCodes.d.ts +11 -0
- package/dist/engineErrorCodes.js +32 -0
- package/dist/engineNoticeCodes.d.ts +39 -4
- package/dist/engineNoticeCodes.js +117 -161
- package/dist/engineWireFor.d.ts +43 -0
- package/dist/engineWireFor.js +399 -0
- package/dist/engineWireSdk.d.ts +6 -0
- package/dist/fileHistoryCaptureCapability.d.ts +4 -1
- package/dist/fileHistoryCaptureCapability.js +43 -9
- package/dist/gateVocabulary.d.ts +1 -2
- package/dist/gateVocabulary.js +1 -22
- package/dist/generated/engineNoticeTables.d.ts +3 -0
- package/dist/generated/engineNoticeTables.js +156 -0
- package/dist/generated/toolNameTables.d.ts +2 -0
- package/dist/generated/toolNameTables.js +43 -0
- package/dist/headlessPermissionModeWire.js +2 -4
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +1 -1
- package/dist/hitl/frameRouter.js +4 -2
- package/dist/hitl/hitlHostSurface.js +1 -1
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +11 -3
- package/dist/hitl/planReviewWire.d.ts +41 -3
- package/dist/hitl/planReviewWire.js +264 -49
- package/dist/hitl/rosterMountedNames.d.ts +2 -0
- package/dist/hitl/rosterMountedNames.js +38 -0
- package/dist/hitl/sessionPolicyDeliverable.d.ts +8 -2
- package/dist/hitl/sessionPolicyDeliverable.js +39 -48
- package/dist/hitl/sessionPolicyWire.d.ts +40 -0
- package/dist/hitl/sessionPolicyWire.js +173 -0
- package/dist/hitl/toolApprovalWire.d.ts +4 -2
- package/dist/hitl/toolApprovalWire.js +6 -4
- package/dist/index.d.ts +10 -3
- package/dist/index.js +7 -2
- package/dist/liveInitToolFace.js +28 -10
- package/dist/permissionWireCaps.d.ts +2 -1
- package/dist/permissionWireCaps.js +2 -7
- package/dist/request/taskRequest.d.ts +2 -0
- package/dist/request/taskRequest.js +18 -1
- package/dist/resumeRefusalCopy.d.ts +11 -0
- package/dist/resumeRefusalCopy.js +42 -2
- package/dist/runTerminal.js +4 -0
- package/dist/sandboxWire.js +1 -1
- package/dist/sealedKeyCapability.d.ts +17 -0
- package/dist/sealedKeyCapability.js +42 -0
- package/dist/seatContract.d.ts +2 -1
- package/dist/seatContract.js +5 -21
- package/dist/subagent/engineCompactWire.d.ts +13 -2
- package/dist/subagent/engineCompactWire.js +48 -37
- package/dist/subagent/engineDelegatedPrompt.d.ts +9 -1
- package/dist/subagent/engineDelegatedPrompt.js +16 -16
- package/dist/subagent/engineRowStopGate.d.ts +2 -2
- package/dist/subagent/engineRowStopGate.js +4 -4
- package/dist/subagent/engineSubagentOutput.d.ts +8 -0
- package/dist/subagent/engineSubagentOutput.js +37 -18
- package/dist/subagent/engineSubagentResume.d.ts +11 -2
- package/dist/subagent/engineSubagentResume.js +28 -14
- package/dist/subagent/engineSubagentSteer.d.ts +10 -1
- package/dist/subagent/engineSubagentSteer.js +16 -11
- package/dist/subagent/engineSubagentTail.d.ts +10 -1
- package/dist/subagent/engineSubagentTail.js +35 -17
- package/dist/subagent/engineTaskHandleWire.d.ts +13 -0
- package/dist/subagent/engineTaskHandleWire.js +41 -20
- package/dist/systemReminderTag.d.ts +5 -0
- package/dist/systemReminderTag.js +20 -9
- package/dist/taskRequestWords.d.ts +5 -0
- package/dist/taskRequestWords.js +4 -0
- package/dist/wireErrorTriage.d.ts +1 -0
- package/dist/wireErrorTriage.js +3 -1
- package/dist/wireRefusalCopy.d.ts +10 -0
- package/dist/wireRefusalCopy.js +62 -2
- package/docs/INTEGRATION-CLIENTS.md +1128 -22
- package/package.json +1 -1
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
|
-
import {
|
|
3
|
-
import { engineWireTargetFor } from '../engineWireTarget.js';
|
|
2
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, settleInjected } from '../engineWireFor.js';
|
|
4
3
|
import { engineSessionParamFor } from '../engineSessionParam.js';
|
|
5
4
|
import { resolveOwnerContext } from './engineSubagentResume.js';
|
|
6
5
|
import { noteBgOwnerAbsence } from './subagentOwnerAbsence.js';
|
|
6
|
+
function usableReportClient(client) {
|
|
7
|
+
return clientHasVerbs(client, [['capabilities'], ['runs', 'subagentOutput']]);
|
|
8
|
+
}
|
|
7
9
|
const capByBase = new Map();
|
|
8
10
|
const CAP_FALSE_RETRY_TTL_MS = 5 * 60_000;
|
|
9
|
-
async function subagentOutputCapable(client,
|
|
10
|
-
const hit = capByBase.get(
|
|
11
|
+
async function subagentOutputCapable(client, cacheKey, signal, deadlineMs) {
|
|
12
|
+
const hit = cacheKey !== undefined ? capByBase.get(cacheKey) : undefined;
|
|
11
13
|
if (hit && (hit.ok || Date.now() - hit.at < CAP_FALSE_RETRY_TTL_MS))
|
|
12
14
|
return hit.ok;
|
|
13
15
|
try {
|
|
14
|
-
const caps =
|
|
16
|
+
const caps = deadlineMs !== undefined
|
|
17
|
+
? await settleInjected(deadlineMs, signal, (s) => client.capabilities({ signal: s }))
|
|
18
|
+
: await client.capabilities({ ...(signal ? { signal } : {}) });
|
|
15
19
|
const ok = caps.subagentOutput === true;
|
|
16
|
-
|
|
20
|
+
if (cacheKey !== undefined)
|
|
21
|
+
capByBase.set(cacheKey, { ok, at: Date.now() });
|
|
17
22
|
return ok;
|
|
18
23
|
}
|
|
19
24
|
catch {
|
|
@@ -25,28 +30,42 @@ export function __resetSubagentOutputCapCacheForTests() {
|
|
|
25
30
|
}
|
|
26
31
|
export async function fetchEngineSubagentReport(taskId, opts) {
|
|
27
32
|
const { record: owner, runId, key } = resolveOwnerContext(taskId);
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
33
|
+
const wire = engineWireFor(opts?.wire, key, usableReportClient);
|
|
34
|
+
if (wire.kind === 'no-target')
|
|
35
|
+
return null;
|
|
36
|
+
if (wire.kind === 'injected-unusable') {
|
|
37
|
+
hostLog('debug', `[subagent-output] ${taskId}: the engine client supplied by the host is not usable (needs capabilities and runs.subagentOutput) — nothing sent`);
|
|
30
38
|
return null;
|
|
39
|
+
}
|
|
31
40
|
if (!runId) {
|
|
32
41
|
noteBgOwnerAbsence('subagent-output', taskId);
|
|
33
42
|
return null;
|
|
34
43
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
let client;
|
|
45
|
+
let cacheKey;
|
|
46
|
+
let injected;
|
|
47
|
+
if (wire.kind === 'injected') {
|
|
48
|
+
client = wire.client;
|
|
49
|
+
cacheKey = wire.capsBaseUrl;
|
|
50
|
+
injected = true;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const made = wire.make();
|
|
54
|
+
if (!made)
|
|
55
|
+
return null;
|
|
56
|
+
client = made;
|
|
57
|
+
cacheKey = wire.target.baseUrl;
|
|
58
|
+
injected = false;
|
|
59
|
+
}
|
|
60
|
+
if (!(await subagentOutputCapable(client, cacheKey, opts?.signal, injected ? INJECTED_WIRE_SETTLE_MS : undefined)))
|
|
43
61
|
return null;
|
|
44
62
|
try {
|
|
45
63
|
const session = owner?.sessionId ?? engineSessionParamFor(key);
|
|
46
|
-
const
|
|
47
|
-
...(
|
|
64
|
+
const read = (signal) => client.runs.subagentOutput(runId, taskId, {
|
|
65
|
+
...(signal ? { signal } : {}),
|
|
48
66
|
...(session ? { session } : {}),
|
|
49
67
|
});
|
|
68
|
+
const r = injected ? await settleInjected(INJECTED_WIRE_SETTLE_MS, opts?.signal, read) : await read(opts?.signal);
|
|
50
69
|
const content = typeof r?.content === 'string' ? r.content : '';
|
|
51
70
|
if (!content.trim())
|
|
52
71
|
return null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { SubagentSteerReceipt } from '@sema-agent/sdk';
|
|
1
|
+
import type { AgentClient, SubagentSteerReceipt } from '@sema-agent/sdk';
|
|
2
|
+
import type { EngineWireInjection } from '../engineWireSdk.js';
|
|
2
3
|
import { type SubagentOwnerRecord } from '../subagentContentStore.js';
|
|
3
4
|
export declare const SUBAGENT_RESUME_CAP = "subagentResume";
|
|
4
5
|
export declare function subagentResumeAvailable(baseUrl?: string, sessionKey?: string): boolean;
|
|
@@ -21,12 +22,14 @@ export type SubagentResumeOutcome = {
|
|
|
21
22
|
detail: string;
|
|
22
23
|
retryAfterSec?: number;
|
|
23
24
|
code?: string;
|
|
25
|
+
unconfirmed?: true;
|
|
24
26
|
};
|
|
25
27
|
export interface SubagentResumeFailureVerdict {
|
|
26
28
|
reason: SubagentResumeFailureKind;
|
|
27
29
|
detail: string;
|
|
28
30
|
retryAfterSec?: number;
|
|
29
31
|
code?: string;
|
|
32
|
+
unconfirmed?: true;
|
|
30
33
|
}
|
|
31
34
|
export declare function classifySubagentResumeFailure(e: unknown): SubagentResumeFailureVerdict;
|
|
32
35
|
export declare function resolveOwnerRunId(childTaskId?: string, activeRunId?: string | undefined): string | undefined;
|
|
@@ -41,7 +44,13 @@ export interface SubagentResumeContext {
|
|
|
41
44
|
runId: string | undefined;
|
|
42
45
|
session: Record<string, string>;
|
|
43
46
|
}
|
|
44
|
-
export
|
|
47
|
+
export type SubagentResumeWireClient = {
|
|
48
|
+
runs: Pick<AgentClient['runs'], 'resumeSubagent'>;
|
|
49
|
+
};
|
|
50
|
+
export type SubagentResumeWire = EngineWireInjection<SubagentResumeWireClient>;
|
|
51
|
+
export declare function resolveSubagentResumeContext(childTaskId?: string, opts?: {
|
|
52
|
+
wire?: SubagentResumeWire;
|
|
53
|
+
}): SubagentResumeContext;
|
|
45
54
|
export declare function resumeSettledSubagent(facade: SubagentResumeFacade | null, runId: string | undefined, target: string, content: string, opts?: {
|
|
46
55
|
session?: string;
|
|
47
56
|
signal?: AbortSignal;
|
|
@@ -2,7 +2,7 @@ import { hostLog } from '../host.js';
|
|
|
2
2
|
import { resumeRetryLaterFromError } from '../wireErrorTriage.js';
|
|
3
3
|
import { displayUntrusted } from '../displayUntrusted.js';
|
|
4
4
|
import { engineCapTrue } from '../engineCapsCache.js';
|
|
5
|
-
import {
|
|
5
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, sendOnce, settleInjected } from '../engineWireFor.js';
|
|
6
6
|
import { engineWireTargetFor } from '../engineWireTarget.js';
|
|
7
7
|
import { activeEngineRunId, engineSessionParamFor } from '../engineSessionParam.js';
|
|
8
8
|
import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
@@ -33,6 +33,11 @@ function shapeOf(e) {
|
|
|
33
33
|
}
|
|
34
34
|
export function classifySubagentResumeFailure(e) {
|
|
35
35
|
const { status, errorCode, message } = shapeOf(e);
|
|
36
|
+
if (status === undefined && errorCode === undefined) {
|
|
37
|
+
const noAnswer = typeof e === 'object' ? noAnswerDetailFrom(e) : null;
|
|
38
|
+
if (noAnswer !== null)
|
|
39
|
+
return { reason: 'error', detail: noAnswer, unconfirmed: true };
|
|
40
|
+
}
|
|
36
41
|
const retryLater = resumeRetryLaterFromError(e);
|
|
37
42
|
if (retryLater !== null) {
|
|
38
43
|
return {
|
|
@@ -77,18 +82,27 @@ export function resolveOwnerContext(childTaskId) {
|
|
|
77
82
|
const record = getBgParentRunOwner(childTaskId);
|
|
78
83
|
return { record, runId: record?.runId, key: record?.sessionKey ?? DEFAULT_SESSION_KEY };
|
|
79
84
|
}
|
|
80
|
-
|
|
85
|
+
function usableResumeClient(client) {
|
|
86
|
+
return clientHasVerbs(client, [['runs', 'resumeSubagent']]);
|
|
87
|
+
}
|
|
88
|
+
export function resolveSubagentResumeContext(childTaskId, opts) {
|
|
81
89
|
const { record: owner, key } = resolveOwnerContext(childTaskId);
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
84
|
-
return { facade: null, runId: undefined, session: {} };
|
|
85
|
-
const client = makeEngineWireClient({
|
|
86
|
-
baseUrl: cfg.baseUrl,
|
|
87
|
-
...(cfg.token ? { token: cfg.token } : {}),
|
|
88
|
-
...(cfg.principal !== undefined ? { principal: cfg.principal } : {}),
|
|
89
|
-
});
|
|
90
|
-
if (!client)
|
|
90
|
+
const wire = engineWireFor(opts?.wire, key, usableResumeClient);
|
|
91
|
+
if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
|
|
91
92
|
return { facade: null, runId: undefined, session: {} };
|
|
93
|
+
let facade;
|
|
94
|
+
if (wire.kind === 'injected') {
|
|
95
|
+
const injected = wire.client;
|
|
96
|
+
facade = {
|
|
97
|
+
resumeSubagent: (taskId, target, message, o) => settleInjected(INJECTED_WIRE_SETTLE_MS, o?.signal, (signal) => injected.runs.resumeSubagent(taskId, target, message, { ...(o?.session !== undefined ? { session: o.session } : {}), signal })),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const client = wire.make();
|
|
102
|
+
if (!client)
|
|
103
|
+
return { facade: null, runId: undefined, session: {} };
|
|
104
|
+
facade = client.runs;
|
|
105
|
+
}
|
|
92
106
|
const named = childTaskId !== undefined && childTaskId !== '';
|
|
93
107
|
const sessionFromRow = owner?.sessionId;
|
|
94
108
|
const fallback = named ? undefined : engineSessionParamFor(key);
|
|
@@ -97,7 +111,7 @@ export function resolveSubagentResumeContext(childTaskId) {
|
|
|
97
111
|
: fallback !== undefined
|
|
98
112
|
? { session: fallback }
|
|
99
113
|
: {};
|
|
100
|
-
return { facade
|
|
114
|
+
return { facade, runId: resolveOwnerRunId(childTaskId), session };
|
|
101
115
|
}
|
|
102
116
|
function clean(v, max = 200) {
|
|
103
117
|
return displayUntrusted(String(v ?? ''), { credentialUrls: false, credentialWords: false, foldLines: false, mark: 'dot', max });
|
|
@@ -111,7 +125,7 @@ export async function resumeSettledSubagent(facade, runId, target, content, opts
|
|
|
111
125
|
if (text === '')
|
|
112
126
|
return { ok: false, reason: 'bad-request', detail: 'empty message' };
|
|
113
127
|
try {
|
|
114
|
-
const receipt = await facade.resumeSubagent(runId, target, { content: text }, opts);
|
|
128
|
+
const receipt = await sendOnce(opts?.signal, () => facade.resumeSubagent(runId, target, { content: text }, opts));
|
|
115
129
|
const note = receipt?.note;
|
|
116
130
|
return {
|
|
117
131
|
ok: true,
|
|
@@ -122,7 +136,7 @@ export async function resumeSettledSubagent(facade, runId, target, content, opts
|
|
|
122
136
|
}
|
|
123
137
|
catch (e) {
|
|
124
138
|
const f = classifySubagentResumeFailure(e);
|
|
125
|
-
hostLog('debug', `engineSubagentResume: resume(${clean(target, 64)}) → ${f.reason} (${clean(f.detail, 160)})`);
|
|
139
|
+
hostLog('debug', `engineSubagentResume: resume(${clean(target, 64)}) → ${f.reason}${f.unconfirmed === true ? ' (may have been received, no answer)' : ''} (${clean(f.detail, 160)})`);
|
|
126
140
|
return { ok: false, ...f };
|
|
127
141
|
}
|
|
128
142
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type { AgentClient } from '@sema-agent/sdk';
|
|
2
|
+
import type { EngineWireInjection } from '../engineWireSdk.js';
|
|
3
|
+
export type SubagentSteerWireClient = {
|
|
4
|
+
runs: Pick<AgentClient['runs'], 'steerSubagent'>;
|
|
5
|
+
};
|
|
6
|
+
export type SubagentSteerWire = EngineWireInjection<SubagentSteerWireClient>;
|
|
1
7
|
export type SubagentSteerOutcome = {
|
|
2
8
|
ok: true;
|
|
3
9
|
receipt: string;
|
|
@@ -5,5 +11,8 @@ export type SubagentSteerOutcome = {
|
|
|
5
11
|
ok: false;
|
|
6
12
|
reason: 'no-wire' | 'no-run' | 'not-running' | 'error';
|
|
7
13
|
detail?: string;
|
|
14
|
+
unconfirmed?: true;
|
|
8
15
|
};
|
|
9
|
-
export declare function steerEngineSubagent(target: string, text: string, childTaskId?: string
|
|
16
|
+
export declare function steerEngineSubagent(target: string, text: string, childTaskId?: string, opts?: {
|
|
17
|
+
wire?: SubagentSteerWire;
|
|
18
|
+
}): Promise<SubagentSteerOutcome>;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
|
-
import {
|
|
3
|
-
import { engineWireTargetFor } from '../engineWireTarget.js';
|
|
2
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, settleInjected } from '../engineWireFor.js';
|
|
4
3
|
import { engineSessionParamFor } from '../engineSessionParam.js';
|
|
5
4
|
import { resolveOwnerContext, resolveOwnerRunId } from './engineSubagentResume.js';
|
|
6
5
|
import { noteBgOwnerAbsence } from './subagentOwnerAbsence.js';
|
|
7
|
-
|
|
6
|
+
function usableSteerClient(client) {
|
|
7
|
+
return clientHasVerbs(client, [['runs', 'steerSubagent']]);
|
|
8
|
+
}
|
|
9
|
+
export async function steerEngineSubagent(target, text, childTaskId, opts) {
|
|
8
10
|
const named = typeof childTaskId === 'string' && childTaskId !== '' ? childTaskId : undefined;
|
|
9
11
|
const { record: owner, key } = resolveOwnerContext(named);
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
12
|
+
const wire = engineWireFor(opts?.wire, key, usableSteerClient);
|
|
13
|
+
if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
|
|
12
14
|
return { ok: false, reason: 'no-wire' };
|
|
13
15
|
const runId = resolveOwnerRunId(named);
|
|
14
16
|
if (!runId) {
|
|
@@ -16,11 +18,7 @@ export async function steerEngineSubagent(target, text, childTaskId) {
|
|
|
16
18
|
noteBgOwnerAbsence('subagent-steer', named);
|
|
17
19
|
return { ok: false, reason: 'no-run' };
|
|
18
20
|
}
|
|
19
|
-
const client =
|
|
20
|
-
baseUrl: cfg.baseUrl,
|
|
21
|
-
...(cfg.token ? { token: cfg.token } : {}),
|
|
22
|
-
principal: cfg.principal,
|
|
23
|
-
});
|
|
21
|
+
const client = wire.kind === 'injected' ? wire.client : wire.make();
|
|
24
22
|
if (!client)
|
|
25
23
|
return { ok: false, reason: 'no-wire' };
|
|
26
24
|
const rowSession = owner?.sessionId;
|
|
@@ -31,7 +29,9 @@ export async function steerEngineSubagent(target, text, childTaskId) {
|
|
|
31
29
|
? { session: fallbackSession }
|
|
32
30
|
: {};
|
|
33
31
|
try {
|
|
34
|
-
const body =
|
|
32
|
+
const body = wire.kind === 'injected'
|
|
33
|
+
? await settleInjected(INJECTED_WIRE_SETTLE_MS, undefined, (signal) => client.runs.steerSubagent(runId, target, { content: text }, { ...session, signal }))
|
|
34
|
+
: await client.runs.steerSubagent(runId, target, { content: text }, session);
|
|
35
35
|
let receipt = 'Message queued for delivery at the next tool round.';
|
|
36
36
|
const copy = body?.note ?? body?.message;
|
|
37
37
|
if (typeof copy === 'string' && copy.length > 0)
|
|
@@ -48,6 +48,11 @@ export async function steerEngineSubagent(target, text, childTaskId) {
|
|
|
48
48
|
}
|
|
49
49
|
return { ok: false, reason: 'error', detail: `${status}` };
|
|
50
50
|
}
|
|
51
|
+
const noAnswer = typeof e === 'object' ? noAnswerDetailFrom(e) : null;
|
|
52
|
+
if (noAnswer !== null) {
|
|
53
|
+
hostLog('debug', `engineSubagentSteer: may have been received, no answer — ${noAnswer}`);
|
|
54
|
+
return { ok: false, reason: 'error', detail: noAnswer, unconfirmed: true };
|
|
55
|
+
}
|
|
51
56
|
hostLog('debug', `engineSubagentSteer: fetch failed ${String(e)}`);
|
|
52
57
|
return { ok: false, reason: 'error', detail: String(e) };
|
|
53
58
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type { AgentClient } from '@sema-agent/sdk';
|
|
2
|
+
import type { EngineWireInjection } from '../engineWireSdk.js';
|
|
3
|
+
export type SubagentTailWireClient = {
|
|
4
|
+
capabilities: AgentClient['capabilities'];
|
|
5
|
+
runs: Pick<AgentClient['runs'], 'subagentStream'>;
|
|
6
|
+
};
|
|
7
|
+
export type SubagentTailWire = EngineWireInjection<SubagentTailWireClient>;
|
|
1
8
|
export declare function __resetSubagentStreamCapCacheForTests(): void;
|
|
2
9
|
export interface SubagentActivity {
|
|
3
10
|
taskId: string;
|
|
@@ -14,7 +21,9 @@ export interface SubagentTailMeta {
|
|
|
14
21
|
export type SubagentTailMetaSink = (m: SubagentTailMeta) => void;
|
|
15
22
|
export declare function installSubagentTailMetaSink(sink: SubagentTailMetaSink | null): () => void;
|
|
16
23
|
export declare function isEngineSubagentTailActive(taskId: string): boolean;
|
|
17
|
-
export declare function tailEngineSubagent(taskId: string
|
|
24
|
+
export declare function tailEngineSubagent(taskId: string, opts?: {
|
|
25
|
+
wire?: SubagentTailWire;
|
|
26
|
+
}): void;
|
|
18
27
|
export declare function stopEngineSubagentTail(taskId: string): void;
|
|
19
28
|
export declare function hasActiveSubagentTail(taskId: string): boolean;
|
|
20
29
|
export declare function __activeTailCountForTests(): number;
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
|
-
import {
|
|
3
|
-
import { engineWireTargetFor } from '../engineWireTarget.js';
|
|
2
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, settleInjected } from '../engineWireFor.js';
|
|
4
3
|
import { engineSessionParamFor } from '../engineSessionParam.js';
|
|
5
4
|
import { resolveOwnerContext } from './engineSubagentResume.js';
|
|
6
5
|
import { coerceOutput, parentToolCallIdOf, publishSubagentContentEvent, settleSubagentContent, } from '../subagentContentStore.js';
|
|
7
6
|
import { noteBgOwnerAbsence } from './subagentOwnerAbsence.js';
|
|
7
|
+
function usableTailClient(client) {
|
|
8
|
+
return clientHasVerbs(client, [['capabilities'], ['runs', 'subagentStream']]);
|
|
9
|
+
}
|
|
8
10
|
const capByBase = new Map();
|
|
9
11
|
const CAP_FALSE_RETRY_TTL_MS = 5 * 60_000;
|
|
10
|
-
async function subagentStreamCapable(client,
|
|
11
|
-
const hit = capByBase.get(
|
|
12
|
+
async function subagentStreamCapable(client, cacheKey, signal, deadlineMs) {
|
|
13
|
+
const hit = cacheKey !== undefined ? capByBase.get(cacheKey) : undefined;
|
|
12
14
|
if (hit && (hit.ok || Date.now() - hit.at < CAP_FALSE_RETRY_TTL_MS))
|
|
13
15
|
return hit.ok;
|
|
14
16
|
try {
|
|
15
|
-
const caps =
|
|
17
|
+
const caps = deadlineMs !== undefined
|
|
18
|
+
? await settleInjected(deadlineMs, signal, (s) => client.capabilities({ signal: s }))
|
|
19
|
+
: await client.capabilities({ ...(signal ? { signal } : {}) });
|
|
16
20
|
const ok = caps.subagentStream === true;
|
|
17
|
-
|
|
21
|
+
if (cacheKey !== undefined)
|
|
22
|
+
capByBase.set(cacheKey, { ok, at: Date.now() });
|
|
18
23
|
return ok;
|
|
19
24
|
}
|
|
20
25
|
catch {
|
|
@@ -44,24 +49,37 @@ export function installSubagentTailMetaSink(sink) {
|
|
|
44
49
|
export function isEngineSubagentTailActive(taskId) {
|
|
45
50
|
return activeTails.has(taskId);
|
|
46
51
|
}
|
|
47
|
-
export function tailEngineSubagent(taskId) {
|
|
52
|
+
export function tailEngineSubagent(taskId, opts) {
|
|
48
53
|
if (activeTails.has(taskId))
|
|
49
54
|
return;
|
|
50
55
|
const { record: owner, runId, key } = resolveOwnerContext(taskId);
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
56
|
+
const wire = engineWireFor(opts?.wire, key, usableTailClient);
|
|
57
|
+
if (wire.kind === 'no-target')
|
|
58
|
+
return;
|
|
59
|
+
if (wire.kind === 'injected-unusable') {
|
|
60
|
+
hostLog('debug', `[subagent-tail] ${taskId}: the engine client supplied by the host is not usable (needs capabilities and runs.subagentStream) — tail not opened`);
|
|
53
61
|
return;
|
|
62
|
+
}
|
|
54
63
|
if (!runId) {
|
|
55
64
|
noteBgOwnerAbsence('subagent-tail', taskId);
|
|
56
65
|
return;
|
|
57
66
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
let client;
|
|
68
|
+
let cacheKey;
|
|
69
|
+
let injected;
|
|
70
|
+
if (wire.kind === 'injected') {
|
|
71
|
+
client = wire.client;
|
|
72
|
+
cacheKey = wire.capsBaseUrl;
|
|
73
|
+
injected = true;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const made = wire.make();
|
|
77
|
+
if (!made)
|
|
78
|
+
return;
|
|
79
|
+
client = made;
|
|
80
|
+
cacheKey = wire.target.baseUrl;
|
|
81
|
+
injected = false;
|
|
82
|
+
}
|
|
65
83
|
const ac = new AbortController();
|
|
66
84
|
activeTails.set(taskId, ac);
|
|
67
85
|
const openedAt = Date.now();
|
|
@@ -70,7 +88,7 @@ export function tailEngineSubagent(taskId) {
|
|
|
70
88
|
let firstContentLogged = false;
|
|
71
89
|
void (async () => {
|
|
72
90
|
try {
|
|
73
|
-
if (!(await subagentStreamCapable(client,
|
|
91
|
+
if (!(await subagentStreamCapable(client, cacheKey, ac.signal, injected ? INJECTED_WIRE_SETTLE_MS : undefined)))
|
|
74
92
|
return;
|
|
75
93
|
const session = owner?.sessionId ?? engineSessionParamFor(key);
|
|
76
94
|
const stream = client.runs.subagentStream(runId, taskId, {
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { type AgentClient } from '@sema-agent/sdk';
|
|
2
|
+
import type { EngineWireInjection } from '../engineWireSdk.js';
|
|
3
|
+
export type EngineTaskOutputWireClient = {
|
|
4
|
+
runs: Pick<AgentClient['runs'], 'taskOutput'>;
|
|
5
|
+
};
|
|
6
|
+
export type EngineTaskOutputWire = EngineWireInjection<EngineTaskOutputWireClient>;
|
|
7
|
+
export type EngineTaskStopWireClient = {
|
|
8
|
+
runs: Pick<AgentClient['runs'], 'taskStop'>;
|
|
9
|
+
};
|
|
10
|
+
export type EngineTaskStopWire = EngineWireInjection<EngineTaskStopWireClient>;
|
|
1
11
|
export interface EngineTaskOutputResult {
|
|
2
12
|
content: string;
|
|
3
13
|
status?: string;
|
|
@@ -7,6 +17,7 @@ export interface EngineTaskOutputResult {
|
|
|
7
17
|
export declare function __resetTaskHandleWireForTests(): void;
|
|
8
18
|
export declare function fetchEngineTaskOutput(handle: string, opts?: {
|
|
9
19
|
signal?: AbortSignal;
|
|
20
|
+
wire?: EngineTaskOutputWire;
|
|
10
21
|
}): Promise<EngineTaskOutputResult | null>;
|
|
11
22
|
export interface TaskOutputMergeHint {
|
|
12
23
|
readonly type?: string;
|
|
@@ -41,8 +52,10 @@ export type EngineTaskStopOutcome = {
|
|
|
41
52
|
ok: false;
|
|
42
53
|
reason: 'unavailable' | 'error';
|
|
43
54
|
detail?: string;
|
|
55
|
+
unconfirmed?: true;
|
|
44
56
|
};
|
|
45
57
|
export declare function classifyTaskStopConflict(e: unknown): EngineTaskStopOutcome;
|
|
46
58
|
export declare function stopEngineTask(handle: string, opts?: {
|
|
47
59
|
signal?: AbortSignal;
|
|
60
|
+
wire?: EngineTaskStopWire;
|
|
48
61
|
}): Promise<EngineTaskStopOutcome>;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { TaskStopConflictError } from '@sema-agent/sdk';
|
|
2
2
|
import { hostLog } from '../host.js';
|
|
3
|
-
import {
|
|
4
|
-
import { engineWireDebugEnabled
|
|
3
|
+
import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, sendOnce, settleInjected } from '../engineWireFor.js';
|
|
4
|
+
import { engineWireDebugEnabled } from '../engineWireTarget.js';
|
|
5
|
+
import { engineCapTrue } from '../engineCapsCache.js';
|
|
5
6
|
import { engineSessionParamFor } from '../engineSessionParam.js';
|
|
6
7
|
import { resolveOwnerContext } from './engineSubagentResume.js';
|
|
7
8
|
import { engineTaskHandlesCapable } from './engineRowStopGate.js';
|
|
8
9
|
import { noteBgOwnerAbsence } from './subagentOwnerAbsence.js';
|
|
10
|
+
function usableTaskOutputClient(client) {
|
|
11
|
+
return clientHasVerbs(client, [['runs', 'taskOutput']]);
|
|
12
|
+
}
|
|
13
|
+
function usableTaskStopClient(client) {
|
|
14
|
+
return clientHasVerbs(client, [['runs', 'taskStop']]);
|
|
15
|
+
}
|
|
16
|
+
const CAPS_KEY_REQUIRED_DETAIL = 'capability evidence for taskHandles is not available under the key the host named (capsBaseUrl) — nothing sent';
|
|
9
17
|
import { spoolMarkerOf } from '../toolResult.js';
|
|
10
18
|
import { STOP_CONFLICT_CODES, STOP_NOT_LANDED, STOP_NOT_LOCAL, STOP_PARKED, STOP_PARK_ARBITER_UNREACHABLE, STOP_PARK_RESUME_WON, } from '../engineErrorCodes.js';
|
|
11
19
|
function resolveHostRun(handle) {
|
|
@@ -26,24 +34,30 @@ export function __resetTaskHandleWireForTests() {
|
|
|
26
34
|
}
|
|
27
35
|
export async function fetchEngineTaskOutput(handle, opts) {
|
|
28
36
|
const owner = resolveOwnerContext(handle);
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
37
|
+
const wire = engineWireFor(opts?.wire, owner.key, usableTaskOutputClient);
|
|
38
|
+
if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
|
|
39
|
+
return null;
|
|
40
|
+
if (wire.kind === 'injected') {
|
|
41
|
+
if (!engineCapTrue(wire.capsBaseUrl, 'taskHandles')) {
|
|
42
|
+
hostLog('debug', `[task-handle] output ${handle}: ${CAPS_KEY_REQUIRED_DETAIL}`);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (!engineTaskHandlesCapable(owner.key)) {
|
|
31
47
|
return null;
|
|
48
|
+
}
|
|
32
49
|
const runId = resolveHostRun(handle);
|
|
33
50
|
if (!runId)
|
|
34
51
|
return null;
|
|
35
|
-
const client =
|
|
36
|
-
baseUrl: cfg.baseUrl,
|
|
37
|
-
...(cfg.token ? { token: cfg.token } : {}),
|
|
38
|
-
principal: cfg.principal,
|
|
39
|
-
});
|
|
52
|
+
const client = wire.kind === 'injected' ? wire.client : wire.make();
|
|
40
53
|
if (!client)
|
|
41
54
|
return null;
|
|
42
55
|
try {
|
|
43
|
-
const
|
|
44
|
-
...(
|
|
56
|
+
const read = (signal) => client.runs.taskOutput(runId, handle, {
|
|
57
|
+
...(signal ? { signal } : {}),
|
|
45
58
|
...(sessionOf(owner)),
|
|
46
59
|
});
|
|
60
|
+
const r = wire.kind === 'injected' ? await settleInjected(INJECTED_WIRE_SETTLE_MS, opts?.signal, read) : await read(opts?.signal);
|
|
47
61
|
const fresh = typeof r?.content === 'string' ? r.content : '';
|
|
48
62
|
const prev = accumulated.get(handle) ?? '';
|
|
49
63
|
const cursorSemantics = r?.cursorSemantics;
|
|
@@ -121,24 +135,28 @@ export function classifyTaskStopConflict(e) {
|
|
|
121
135
|
}
|
|
122
136
|
export async function stopEngineTask(handle, opts) {
|
|
123
137
|
const owner = resolveOwnerContext(handle);
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
138
|
+
const wire = engineWireFor(opts?.wire, owner.key, usableTaskStopClient);
|
|
139
|
+
if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
|
|
140
|
+
return { ok: false, reason: 'unavailable' };
|
|
141
|
+
if (wire.kind === 'injected') {
|
|
142
|
+
if (!engineCapTrue(wire.capsBaseUrl, 'taskHandles'))
|
|
143
|
+
return { ok: false, reason: 'unavailable', detail: CAPS_KEY_REQUIRED_DETAIL };
|
|
144
|
+
}
|
|
145
|
+
else if (!engineTaskHandlesCapable(owner.key)) {
|
|
126
146
|
return { ok: false, reason: 'unavailable' };
|
|
147
|
+
}
|
|
127
148
|
const runId = resolveHostRun(handle);
|
|
128
149
|
if (!runId)
|
|
129
150
|
return { ok: false, reason: 'unavailable', detail: 'no host run mapping' };
|
|
130
|
-
const client =
|
|
131
|
-
baseUrl: cfg.baseUrl,
|
|
132
|
-
...(cfg.token ? { token: cfg.token } : {}),
|
|
133
|
-
principal: cfg.principal,
|
|
134
|
-
});
|
|
151
|
+
const client = wire.kind === 'injected' ? wire.client : wire.make();
|
|
135
152
|
if (!client)
|
|
136
153
|
return { ok: false, reason: 'unavailable' };
|
|
137
154
|
try {
|
|
138
|
-
const
|
|
139
|
-
...(
|
|
155
|
+
const stop = (signal) => client.runs.taskStop(runId, handle, {
|
|
156
|
+
...(signal ? { signal } : {}),
|
|
140
157
|
...(sessionOf(owner)),
|
|
141
158
|
});
|
|
159
|
+
const r = wire.kind === 'injected' ? await settleInjected(INJECTED_WIRE_SETTLE_MS, opts?.signal, stop) : await sendOnce(opts?.signal, () => stop(opts?.signal));
|
|
142
160
|
const out = r?.output ?? {};
|
|
143
161
|
if (engineWireDebugEnabled()) {
|
|
144
162
|
hostLog('debug', `[task-handle] stop ${handle} via run ${runId}: ok status=${typeof out.status === 'string' ? out.status : '-'} stoppedBy=${typeof out.stoppedBy === 'string' ? out.stoppedBy : '-'}`);
|
|
@@ -156,6 +174,9 @@ export async function stopEngineTask(handle, opts) {
|
|
|
156
174
|
if (e instanceof TaskStopConflictError || status === 409) {
|
|
157
175
|
return classifyTaskStopConflict(e);
|
|
158
176
|
}
|
|
177
|
+
const noAnswer = typeof e === 'object' ? noAnswerDetailFrom(e) : null;
|
|
178
|
+
if (noAnswer !== null)
|
|
179
|
+
return { ok: false, reason: 'error', detail: noAnswer, unconfirmed: true };
|
|
159
180
|
return { ok: false, reason: 'error', detail };
|
|
160
181
|
}
|
|
161
182
|
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
export interface SystemReminderOpenTagSpan {
|
|
2
|
+
readonly start: number;
|
|
3
|
+
readonly end: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function findSystemReminderOpenTag(text: string, from?: number): SystemReminderOpenTagSpan | null;
|
|
1
6
|
export declare function unwrapSystemReminder(text: string): string;
|
|
2
7
|
export declare function stripSystemReminderBlocks(text: string): string;
|
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
const OPEN_TAG_SOURCE = '<system-reminder(?: mark="[A-Za-z0-9_-]{22}")?>';
|
|
2
2
|
const CLOSE_TAG = '</system-reminder>';
|
|
3
|
-
|
|
3
|
+
function matchOpenTag(text, from, anchored) {
|
|
4
|
+
const re = new RegExp(OPEN_TAG_SOURCE, anchored ? 'y' : 'g');
|
|
5
|
+
re.lastIndex = from;
|
|
6
|
+
const m = re.exec(text);
|
|
7
|
+
return m === null ? null : { start: m.index, end: m.index + m[0].length };
|
|
8
|
+
}
|
|
9
|
+
export function findSystemReminderOpenTag(text, from) {
|
|
10
|
+
if (typeof text !== 'string')
|
|
11
|
+
return null;
|
|
12
|
+
const at = from === undefined ? 0 : from;
|
|
13
|
+
if (!Number.isInteger(at) || at < 0 || at > text.length)
|
|
14
|
+
return null;
|
|
15
|
+
return matchOpenTag(text, at, false);
|
|
16
|
+
}
|
|
4
17
|
export function unwrapSystemReminder(text) {
|
|
5
18
|
const head = text.trimStart();
|
|
6
|
-
const open =
|
|
19
|
+
const open = matchOpenTag(head, 0, true);
|
|
7
20
|
if (open === null)
|
|
8
21
|
return text;
|
|
9
22
|
const whole = head.trimEnd();
|
|
10
|
-
if (!whole.endsWith(CLOSE_TAG) || whole.length - CLOSE_TAG.length < open
|
|
23
|
+
if (!whole.endsWith(CLOSE_TAG) || whole.length - CLOSE_TAG.length < open.end)
|
|
11
24
|
return text;
|
|
12
|
-
return whole.slice(open
|
|
25
|
+
return whole.slice(open.end, whole.length - CLOSE_TAG.length).trim();
|
|
13
26
|
}
|
|
14
27
|
export function stripSystemReminderBlocks(text) {
|
|
15
|
-
const openRe = new RegExp(OPEN_TAG_SOURCE, 'g');
|
|
16
28
|
let out = '';
|
|
17
29
|
let pos = 0;
|
|
18
30
|
for (;;) {
|
|
19
|
-
|
|
20
|
-
const open = openRe.exec(text);
|
|
31
|
+
const open = matchOpenTag(text, pos, false);
|
|
21
32
|
if (open === null)
|
|
22
33
|
break;
|
|
23
|
-
const close = text.indexOf(CLOSE_TAG, open.
|
|
34
|
+
const close = text.indexOf(CLOSE_TAG, open.end);
|
|
24
35
|
if (close === -1)
|
|
25
36
|
break;
|
|
26
|
-
out += text.slice(pos, open.
|
|
37
|
+
out += text.slice(pos, open.start);
|
|
27
38
|
pos = close + CLOSE_TAG.length;
|
|
28
39
|
}
|
|
29
40
|
return pos === 0 ? text : out + text.slice(pos);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TaskRequest } from '@sema-agent/sdk';
|
|
2
|
+
export type TaskRequestReasoningEffort = NonNullable<TaskRequest['reasoningEffort']>;
|
|
3
|
+
export declare const REASONING_EFFORT_WORDS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
4
|
+
export type TaskRequestPermissionMode = NonNullable<TaskRequest['permissionMode']>;
|
|
5
|
+
export declare const PERMISSION_MODE_WORDS: readonly ["default", "plan", "acceptEdits", "bypassPermissions", "auto"];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const REASONING_EFFORT_WORDS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
2
|
+
export const PERMISSION_MODE_WORDS = ['default', 'plan', 'acceptEdits', 'bypassPermissions', 'auto'];
|
|
3
|
+
const _taskRequestWordPins = [true, true, true, true];
|
|
4
|
+
void _taskRequestWordPins;
|
package/dist/wireErrorTriage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readErrorNumber, readErrorString, readErrorStringList } from './wireFailureShape.js';
|
|
2
2
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
3
|
-
import { DRAINING_ERROR_CODE, RESUME_AT_ERROR_CODE_PREFIX, RESUME_POLICY_FOLD_CODE, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
|
|
3
|
+
import { DRAINING_ERROR_CODE, isCorruptSessionCode, RESUME_AT_ERROR_CODE_PREFIX, RESUME_POLICY_FOLD_CODE, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
|
|
4
4
|
export const WIRE_NETWORK_ERROR_PATTERN = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|terminated|other side closed/i;
|
|
5
5
|
function wireErrorDetail(err) {
|
|
6
6
|
const e = err;
|
|
@@ -15,12 +15,14 @@ export function classifyTurnWireError(err) {
|
|
|
15
15
|
const errorCode = typeof e.errorCode === 'string' && e.errorCode.length > 0 ? e.errorCode : undefined;
|
|
16
16
|
const message = typeof e.message === 'string' && e.message.length > 0 ? e.message : String(err);
|
|
17
17
|
const storedRowWhere = corruptStoredRowWhere(err);
|
|
18
|
+
const sessionUnreadable = isCorruptSessionCode(effectiveWireErrorCode(err));
|
|
18
19
|
return {
|
|
19
20
|
kind: 'http',
|
|
20
21
|
status: e.status,
|
|
21
22
|
...(errorCode !== undefined ? { errorCode } : {}),
|
|
22
23
|
message,
|
|
23
24
|
...(storedRowWhere !== undefined ? { storedRowWhere } : {}),
|
|
25
|
+
...(sessionUnreadable ? { sessionUnreadable: true } : {}),
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
const errName = typeof err === 'object' && err !== null && typeof err.name === 'string'
|