@jsonstudio/llms 0.6.1892 → 0.6.2172
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/dist/conversion/compat/actions/deepseek-web-request.js +16 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
- package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
- package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
- package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
- package/dist/conversion/compat/antigravity-session-signature.js +15 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
- package/dist/conversion/compat/profiles/chat-glm.json +22 -0
- package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
- package/dist/conversion/hub/process/chat-process.js +85 -18
- package/dist/conversion/hub/response/provider-response.js +21 -50
- package/dist/conversion/hub/response/response-runtime.js +71 -10
- package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
- package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
- package/dist/conversion/responses/responses-openai-bridge.js +193 -504
- package/dist/conversion/shared/anthropic-message-utils.js +82 -2
- package/dist/conversion/shared/bridge-message-utils.js +92 -39
- package/dist/conversion/shared/snapshot-hooks.js +8 -13
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
- package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
- package/dist/conversion/shared/tool-governor.js +136 -10
- package/dist/filters/utils/snapshot-writer.js +3 -3
- package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
- package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
- package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
- package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/utils.js +41 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
- package/dist/router/virtual-router/bootstrap.d.ts +0 -4
- package/dist/router/virtual-router/bootstrap.js +31 -1275
- package/dist/router/virtual-router/classifier.js +32 -14
- package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
- package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
- package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
- package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
- package/dist/router/virtual-router/engine/route-analytics.js +44 -0
- package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
- package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
- package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
- package/dist/router/virtual-router/engine-logging.d.ts +42 -1
- package/dist/router/virtual-router/engine-logging.js +82 -15
- package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
- package/dist/router/virtual-router/engine.d.ts +21 -7
- package/dist/router/virtual-router/engine.js +198 -194
- package/dist/router/virtual-router/features.js +12 -4
- package/dist/router/virtual-router/message-utils.d.ts +8 -0
- package/dist/router/virtual-router/message-utils.js +170 -45
- package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
- package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
- package/dist/router/virtual-router/routing-instructions.js +18 -2
- package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
- package/dist/router/virtual-router/token-counter.js +51 -10
- package/dist/router/virtual-router/tool-signals.js +4 -0
- package/dist/router/virtual-router/types.d.ts +15 -0
- package/dist/servertool/clock/session-scope.d.ts +3 -0
- package/dist/servertool/clock/session-scope.js +52 -0
- package/dist/servertool/clock/state.js +9 -0
- package/dist/servertool/clock/tasks.js +12 -1
- package/dist/servertool/clock/types.d.ts +3 -0
- package/dist/servertool/engine.js +177 -31
- package/dist/servertool/handlers/clock-auto.js +2 -8
- package/dist/servertool/handlers/clock.js +6 -9
- package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
- package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
- package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
- package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +80 -556
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
- package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
- package/dist/servertool/handlers/web-search.js +117 -0
- package/dist/servertool/server-side-tools.d.ts +0 -1
- package/dist/servertool/server-side-tools.js +4 -3
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
- package/dist/telemetry/stats-center.d.ts +9 -0
- package/dist/telemetry/stats-center.js +29 -1
- package/dist/tools/apply-patch/structured/coercion.js +3 -11
- package/dist/tools/exec-command/validator.d.ts +1 -0
- package/dist/tools/exec-command/validator.js +132 -0
- package/dist/tools/tool-registry.d.ts +1 -0
- package/dist/tools/tool-registry.js +1 -1
- package/package.json +1 -1
|
@@ -64,11 +64,54 @@ function countMessageTokens(message, encoder) {
|
|
|
64
64
|
}
|
|
65
65
|
return total;
|
|
66
66
|
}
|
|
67
|
+
function detectMediaKind(record) {
|
|
68
|
+
const typeValue = typeof record.type === 'string' ? record.type.trim().toLowerCase() : '';
|
|
69
|
+
if (typeValue.includes('video')) {
|
|
70
|
+
return 'video';
|
|
71
|
+
}
|
|
72
|
+
if (typeValue.includes('image')) {
|
|
73
|
+
return 'image';
|
|
74
|
+
}
|
|
75
|
+
if (Object.prototype.hasOwnProperty.call(record, 'video_url')) {
|
|
76
|
+
return 'video';
|
|
77
|
+
}
|
|
78
|
+
if (Object.prototype.hasOwnProperty.call(record, 'image_url')) {
|
|
79
|
+
return 'image';
|
|
80
|
+
}
|
|
81
|
+
const dataField = typeof record.data === 'string' ? record.data.trim().toLowerCase() : '';
|
|
82
|
+
if (dataField.startsWith('data:video/')) {
|
|
83
|
+
return 'video';
|
|
84
|
+
}
|
|
85
|
+
if (dataField.startsWith('data:image/')) {
|
|
86
|
+
return 'image';
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
function parseStructuredContentString(raw) {
|
|
91
|
+
const trimmed = raw.trim();
|
|
92
|
+
if (!trimmed) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const likelyJson = (trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'));
|
|
96
|
+
if (!likelyJson) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(trimmed);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
67
106
|
function encodeContent(content, encoder) {
|
|
68
107
|
if (content === null || content === undefined) {
|
|
69
108
|
return 0;
|
|
70
109
|
}
|
|
71
110
|
if (typeof content === 'string') {
|
|
111
|
+
const structured = parseStructuredContentString(content);
|
|
112
|
+
if (structured !== undefined) {
|
|
113
|
+
return encodeContent(structured, encoder);
|
|
114
|
+
}
|
|
72
115
|
return encodeText(content, encoder);
|
|
73
116
|
}
|
|
74
117
|
if (Array.isArray(content)) {
|
|
@@ -79,17 +122,11 @@ function encodeContent(content, encoder) {
|
|
|
79
122
|
}
|
|
80
123
|
else if (part && typeof part === 'object') {
|
|
81
124
|
const record = part;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// small textual placeholder instead of the full JSON/body.
|
|
86
|
-
if (typeValue.startsWith('image')) {
|
|
87
|
-
const caption = typeof record.caption === 'string' && record.caption.trim().length
|
|
88
|
-
? record.caption
|
|
89
|
-
: '[image]';
|
|
90
|
-
total += encodeText(caption, encoder);
|
|
125
|
+
// Ignore image/video payload blocks in token estimation.
|
|
126
|
+
if (detectMediaKind(record)) {
|
|
127
|
+
continue;
|
|
91
128
|
}
|
|
92
|
-
|
|
129
|
+
if (typeof record.text === 'string') {
|
|
93
130
|
total += encodeText(record.text, encoder);
|
|
94
131
|
}
|
|
95
132
|
else {
|
|
@@ -100,6 +137,10 @@ function encodeContent(content, encoder) {
|
|
|
100
137
|
return total;
|
|
101
138
|
}
|
|
102
139
|
if (typeof content === 'object') {
|
|
140
|
+
const record = content;
|
|
141
|
+
if (detectMediaKind(record)) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
103
144
|
return encodeText(JSON.stringify(content), encoder);
|
|
104
145
|
}
|
|
105
146
|
return encodeText(String(content), encoder);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const WEB_TOOL_KEYWORDS = ['websearch', 'web_search', 'web-search', 'webfetch', 'web_fetch', 'web_request', 'search_web', 'internet_search'];
|
|
2
2
|
const READ_TOOL_EXACT = new Set([
|
|
3
|
+
'read',
|
|
3
4
|
'read_file',
|
|
4
5
|
'read_text',
|
|
5
6
|
'view_file',
|
|
@@ -11,6 +12,9 @@ const READ_TOOL_EXACT = new Set([
|
|
|
11
12
|
'describe_current_request'
|
|
12
13
|
]);
|
|
13
14
|
const WRITE_TOOL_EXACT = new Set([
|
|
15
|
+
'edit',
|
|
16
|
+
'write',
|
|
17
|
+
'multiedit',
|
|
14
18
|
'apply_patch',
|
|
15
19
|
'write_file',
|
|
16
20
|
'create_file',
|
|
@@ -386,6 +386,9 @@ export interface RoutingFeatures {
|
|
|
386
386
|
hasToolCallResponses: boolean;
|
|
387
387
|
hasVisionTool: boolean;
|
|
388
388
|
hasImageAttachment: boolean;
|
|
389
|
+
hasVideoAttachment?: boolean;
|
|
390
|
+
hasRemoteVideoAttachment?: boolean;
|
|
391
|
+
hasLocalVideoAttachment?: boolean;
|
|
389
392
|
hasWebTool: boolean;
|
|
390
393
|
hasWebSearchToolDeclared?: boolean;
|
|
391
394
|
hasCodingTool: boolean;
|
|
@@ -473,6 +476,9 @@ export interface StopMessageStateSnapshot {
|
|
|
473
476
|
stopMessageObservationHash?: string;
|
|
474
477
|
stopMessageObservationStableCount?: number;
|
|
475
478
|
stopMessageBdWorkState?: string;
|
|
479
|
+
stopMessageAssignedIssueId?: string;
|
|
480
|
+
stopMessageAssignedIssueSource?: 'in_progress' | 'ready' | 'open';
|
|
481
|
+
stopMessageNoTaskSummaryUsed?: boolean;
|
|
476
482
|
}
|
|
477
483
|
export interface PreCommandStateSnapshot {
|
|
478
484
|
preCommandScriptPath: string;
|
|
@@ -484,6 +490,15 @@ export interface RoutingStatusSnapshot {
|
|
|
484
490
|
providers: string[];
|
|
485
491
|
hits: number;
|
|
486
492
|
lastUsedProvider?: string;
|
|
493
|
+
lastHit?: {
|
|
494
|
+
timestampMs: number;
|
|
495
|
+
reason?: string;
|
|
496
|
+
requestTokens?: number;
|
|
497
|
+
selectionPenalty?: number;
|
|
498
|
+
stopMessageActive: boolean;
|
|
499
|
+
stopMessageMode?: 'on' | 'off' | 'auto';
|
|
500
|
+
stopMessageRemaining?: number;
|
|
501
|
+
};
|
|
487
502
|
}>;
|
|
488
503
|
health: ProviderHealthState[];
|
|
489
504
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function buildClockSessionScopeFromDaemonId(daemonId: string): string;
|
|
2
|
+
export declare function extractClockDaemonIdFromSessionScope(sessionScope: string): string | null;
|
|
3
|
+
export declare function resolveClockSessionScope(primary?: Record<string, unknown> | null, fallback?: Record<string, unknown> | null): string | null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const CLOCK_DAEMON_SESSION_PREFIX = 'clockd.';
|
|
2
|
+
function readToken(value) {
|
|
3
|
+
return typeof value === 'string' && value.trim().length ? value.trim() : '';
|
|
4
|
+
}
|
|
5
|
+
function readRecordToken(record, keys) {
|
|
6
|
+
if (!record) {
|
|
7
|
+
return '';
|
|
8
|
+
}
|
|
9
|
+
for (const key of keys) {
|
|
10
|
+
const value = readToken(record[key]);
|
|
11
|
+
if (value) {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
export function buildClockSessionScopeFromDaemonId(daemonId) {
|
|
18
|
+
const normalized = readToken(daemonId);
|
|
19
|
+
if (!normalized) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
return `${CLOCK_DAEMON_SESSION_PREFIX}${normalized}`;
|
|
23
|
+
}
|
|
24
|
+
export function extractClockDaemonIdFromSessionScope(sessionScope) {
|
|
25
|
+
const normalized = readToken(sessionScope);
|
|
26
|
+
if (!normalized.startsWith(CLOCK_DAEMON_SESSION_PREFIX)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const daemonId = normalized.slice(CLOCK_DAEMON_SESSION_PREFIX.length).trim();
|
|
30
|
+
return daemonId || null;
|
|
31
|
+
}
|
|
32
|
+
export function resolveClockSessionScope(primary, fallback) {
|
|
33
|
+
const daemonId = readRecordToken(primary, ['clockDaemonId', 'clockClientDaemonId', 'clock_daemon_id', 'clock_client_daemon_id']) ||
|
|
34
|
+
readRecordToken(fallback, ['clockDaemonId', 'clockClientDaemonId', 'clock_daemon_id', 'clock_client_daemon_id']);
|
|
35
|
+
if (daemonId) {
|
|
36
|
+
const daemonScope = buildClockSessionScopeFromDaemonId(daemonId);
|
|
37
|
+
if (daemonScope) {
|
|
38
|
+
return daemonScope;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const sessionId = readRecordToken(primary, ['sessionId', 'session_id']) ||
|
|
42
|
+
readRecordToken(fallback, ['sessionId', 'session_id']);
|
|
43
|
+
if (sessionId) {
|
|
44
|
+
return sessionId;
|
|
45
|
+
}
|
|
46
|
+
const conversationId = readRecordToken(primary, ['conversationId', 'conversation_id']) ||
|
|
47
|
+
readRecordToken(fallback, ['conversationId', 'conversation_id']);
|
|
48
|
+
if (conversationId) {
|
|
49
|
+
return conversationId;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
@@ -24,6 +24,13 @@ function normalizeRecurrence(raw) {
|
|
|
24
24
|
}
|
|
25
25
|
return { kind, maxRuns };
|
|
26
26
|
}
|
|
27
|
+
function normalizeTaskSetter(raw) {
|
|
28
|
+
const value = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
|
|
29
|
+
if (value === 'agent') {
|
|
30
|
+
return 'agent';
|
|
31
|
+
}
|
|
32
|
+
return 'user';
|
|
33
|
+
}
|
|
27
34
|
export function setClockOffsetMs(value) {
|
|
28
35
|
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
29
36
|
return;
|
|
@@ -68,12 +75,14 @@ export function coerceState(raw, sessionId) {
|
|
|
68
75
|
: undefined;
|
|
69
76
|
const deliveryCount = typeof e.deliveryCount === 'number' && Number.isFinite(e.deliveryCount) ? Math.max(0, Math.floor(e.deliveryCount)) : 0;
|
|
70
77
|
const recurrence = normalizeRecurrence(e.recurrence);
|
|
78
|
+
const setBy = normalizeTaskSetter(e.setBy);
|
|
71
79
|
tasks.push({
|
|
72
80
|
taskId,
|
|
73
81
|
sessionId,
|
|
74
82
|
dueAtMs,
|
|
75
83
|
createdAtMs,
|
|
76
84
|
updatedAtMs,
|
|
85
|
+
setBy,
|
|
77
86
|
task,
|
|
78
87
|
...(tool ? { tool } : {}),
|
|
79
88
|
...(args ? { arguments: args } : {}),
|
|
@@ -50,6 +50,13 @@ function normalizeRecurrence(raw) {
|
|
|
50
50
|
}
|
|
51
51
|
return { kind, maxRuns };
|
|
52
52
|
}
|
|
53
|
+
function normalizeTaskSetter(raw) {
|
|
54
|
+
const value = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
|
|
55
|
+
if (value === 'agent') {
|
|
56
|
+
return 'agent';
|
|
57
|
+
}
|
|
58
|
+
return 'user';
|
|
59
|
+
}
|
|
53
60
|
function resolveRecurringStepMs(recurrence) {
|
|
54
61
|
if (recurrence.kind === 'daily') {
|
|
55
62
|
return 24 * 60 * 60_000;
|
|
@@ -139,6 +146,7 @@ export async function scheduleClockTasks(sessionId, items, config) {
|
|
|
139
146
|
if (item.recurrence && !recurrence) {
|
|
140
147
|
continue;
|
|
141
148
|
}
|
|
149
|
+
const setBy = normalizeTaskSetter(item.setBy);
|
|
142
150
|
const taskId = buildTaskId();
|
|
143
151
|
scheduled.push({
|
|
144
152
|
taskId,
|
|
@@ -146,6 +154,7 @@ export async function scheduleClockTasks(sessionId, items, config) {
|
|
|
146
154
|
dueAtMs: Math.floor(dueAtMs),
|
|
147
155
|
createdAtMs: at,
|
|
148
156
|
updatedAtMs: at,
|
|
157
|
+
setBy,
|
|
149
158
|
task: text,
|
|
150
159
|
...(item.tool ? { tool: item.tool } : {}),
|
|
151
160
|
...(item.arguments ? { arguments: item.arguments } : {}),
|
|
@@ -355,13 +364,15 @@ export async function reserveDueTasksForRequest(args) {
|
|
|
355
364
|
const injectText = due
|
|
356
365
|
.map((t) => {
|
|
357
366
|
const dueAtIso = new Date(t.dueAtMs).toISOString();
|
|
367
|
+
const setAtIso = new Date(t.createdAtMs).toISOString();
|
|
358
368
|
const toolLabel = t.tool ? ` tool=${t.tool}` : '';
|
|
359
369
|
const argsLabel = t.arguments ? ` args=${safeJson(t.arguments)}` : '';
|
|
370
|
+
const setByLabel = t.setBy === 'agent' ? 'agent' : 'user';
|
|
360
371
|
const recurrence = normalizeRecurrence(t.recurrence);
|
|
361
372
|
const recurrenceLabel = recurrence
|
|
362
373
|
? ` recurrence=${recurrence.kind}${recurrence.kind === 'interval' ? `(${recurrence.everyMinutes}m)` : ''} maxRuns=${recurrence.maxRuns} run=${Math.max(0, t.deliveryCount)}/${recurrence.maxRuns}`
|
|
363
374
|
: '';
|
|
364
|
-
return `[scheduled task:${safeQuoted(t.task)}${toolLabel}${argsLabel}${recurrenceLabel} dueAt=${dueAtIso}]`;
|
|
375
|
+
return `[scheduled task:${safeQuoted(t.task)}${toolLabel}${argsLabel}${recurrenceLabel} dueAt=${dueAtIso} setBy=${setByLabel} setAt=${setAtIso}]`;
|
|
365
376
|
})
|
|
366
377
|
.join('\n');
|
|
367
378
|
return { reservation, injectText };
|
|
@@ -4,12 +4,14 @@ export type ClockTaskRecurrence = {
|
|
|
4
4
|
maxRuns: number;
|
|
5
5
|
everyMinutes?: number;
|
|
6
6
|
};
|
|
7
|
+
export type ClockTaskSetter = 'user' | 'agent';
|
|
7
8
|
export type ClockTask = {
|
|
8
9
|
taskId: string;
|
|
9
10
|
sessionId: string;
|
|
10
11
|
dueAtMs: number;
|
|
11
12
|
createdAtMs: number;
|
|
12
13
|
updatedAtMs: number;
|
|
14
|
+
setBy: ClockTaskSetter;
|
|
13
15
|
task: string;
|
|
14
16
|
tool?: string;
|
|
15
17
|
arguments?: Record<string, unknown>;
|
|
@@ -49,6 +51,7 @@ export type ClockConfigSnapshot = {
|
|
|
49
51
|
export type ClockScheduleItem = {
|
|
50
52
|
dueAtMs: number;
|
|
51
53
|
task: string;
|
|
54
|
+
setBy?: ClockTaskSetter;
|
|
52
55
|
tool?: string;
|
|
53
56
|
arguments?: Record<string, unknown>;
|
|
54
57
|
notBeforeRequestId?: string;
|
|
@@ -7,6 +7,7 @@ import { deserializeRoutingInstructionState, serializeRoutingInstructionState }
|
|
|
7
7
|
import { applyHubFollowupPolicyShadow } from './followup-shadow.js';
|
|
8
8
|
import { buildServerToolFollowupChatPayloadFromInjection, extractCapturedChatSeed } from './handlers/followup-request-builder.js';
|
|
9
9
|
import { findNextUndeliveredDueAtMs, listClockTasks, resolveClockConfig } from './clock/task-store.js';
|
|
10
|
+
import { resolveClockSessionScope } from './clock/session-scope.js';
|
|
10
11
|
import { savePendingServerToolInjection } from './pending-session.js';
|
|
11
12
|
import { appendServerToolProgressFileEvent } from './log/progress-file.js';
|
|
12
13
|
import { attachStopGatewayContext, inspectStopGatewaySignal } from './stop-gateway-context.js';
|
|
@@ -46,6 +47,57 @@ function withTimeout(promise, timeoutMs, buildError) {
|
|
|
46
47
|
});
|
|
47
48
|
});
|
|
48
49
|
}
|
|
50
|
+
class ServerToolClientDisconnectedError extends Error {
|
|
51
|
+
code = 'SERVERTOOL_CLIENT_DISCONNECTED';
|
|
52
|
+
}
|
|
53
|
+
function createServerToolClientDisconnectedError(options) {
|
|
54
|
+
const error = new ServerToolClientDisconnectedError(`[servertool] client disconnected during followup` + (options.flowId ? ` flow=${options.flowId}` : ''));
|
|
55
|
+
error.details = {
|
|
56
|
+
requestId: options.requestId,
|
|
57
|
+
flowId: options.flowId
|
|
58
|
+
};
|
|
59
|
+
return error;
|
|
60
|
+
}
|
|
61
|
+
function isServerToolClientDisconnectedError(error) {
|
|
62
|
+
return Boolean(error &&
|
|
63
|
+
typeof error === 'object' &&
|
|
64
|
+
typeof error.code === 'string' &&
|
|
65
|
+
error.code === 'SERVERTOOL_CLIENT_DISCONNECTED');
|
|
66
|
+
}
|
|
67
|
+
function createClientDisconnectWatcher(options) {
|
|
68
|
+
const interval = typeof options.pollIntervalMs === 'number' && Number.isFinite(options.pollIntervalMs) && options.pollIntervalMs > 0
|
|
69
|
+
? Math.max(20, Math.floor(options.pollIntervalMs))
|
|
70
|
+
: 80;
|
|
71
|
+
let timer;
|
|
72
|
+
let active = true;
|
|
73
|
+
const cancel = () => {
|
|
74
|
+
active = false;
|
|
75
|
+
if (timer) {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
timer = undefined;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const promise = new Promise((_resolve, reject) => {
|
|
81
|
+
const check = () => {
|
|
82
|
+
if (!active) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (isAdapterClientDisconnected(options.adapterContext)) {
|
|
86
|
+
cancel();
|
|
87
|
+
reject(createServerToolClientDisconnectedError({
|
|
88
|
+
requestId: options.requestId,
|
|
89
|
+
flowId: options.flowId
|
|
90
|
+
}));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
timer = setTimeout(check, interval);
|
|
94
|
+
timer.unref?.();
|
|
95
|
+
};
|
|
96
|
+
timer = setTimeout(check, interval);
|
|
97
|
+
timer.unref?.();
|
|
98
|
+
});
|
|
99
|
+
return { promise, cancel };
|
|
100
|
+
}
|
|
49
101
|
function isServerToolTimeoutError(error) {
|
|
50
102
|
return Boolean(error &&
|
|
51
103
|
typeof error === 'object' &&
|
|
@@ -194,6 +246,21 @@ function isEmptyClientResponsePayload(payload) {
|
|
|
194
246
|
}
|
|
195
247
|
return true;
|
|
196
248
|
}
|
|
249
|
+
function createEmptyFollowupError(args) {
|
|
250
|
+
const wrapped = new ProviderProtocolError(`[servertool] Followup returned empty response for flow ${args.flowId ?? 'unknown'}`, {
|
|
251
|
+
code: 'SERVERTOOL_EMPTY_FOLLOWUP',
|
|
252
|
+
category: 'EXTERNAL_ERROR',
|
|
253
|
+
details: {
|
|
254
|
+
flowId: args.flowId,
|
|
255
|
+
requestId: args.requestId,
|
|
256
|
+
error: args.lastError instanceof Error ? args.lastError.message : undefined,
|
|
257
|
+
...(args.originalResponseWasEmpty ? { originalResponseWasEmpty: true } : {})
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
wrapped.status = 502;
|
|
261
|
+
wrapped.cause = args.lastError;
|
|
262
|
+
return wrapped;
|
|
263
|
+
}
|
|
197
264
|
function isStopFinishReasonWithoutToolCalls(base) {
|
|
198
265
|
return inspectStopGatewaySignal(base).eligible;
|
|
199
266
|
}
|
|
@@ -204,7 +271,7 @@ async function shouldDisableServerToolTimeoutForClockHold(args) {
|
|
|
204
271
|
}
|
|
205
272
|
const record = args.adapterContext;
|
|
206
273
|
const rt = readRuntimeMetadata(record);
|
|
207
|
-
const sessionId =
|
|
274
|
+
const sessionId = resolveClockSessionScope(record, rt);
|
|
208
275
|
if (!sessionId) {
|
|
209
276
|
return false;
|
|
210
277
|
}
|
|
@@ -526,6 +593,7 @@ export async function runServerToolOrchestration(options) {
|
|
|
526
593
|
}
|
|
527
594
|
const isStopMessageFlow = engineResult.execution.flowId === 'stop_message_flow';
|
|
528
595
|
const isClockHoldFlow = engineResult.execution.flowId === 'clock_hold_flow';
|
|
596
|
+
const isContinueExecutionFlow = engineResult.execution.flowId === 'continue_execution_flow';
|
|
529
597
|
const isEmptyReplyContinue = engineResult.execution.flowId === 'empty_reply_continue';
|
|
530
598
|
const isApplyPatchGuard = engineResult.execution.flowId === 'apply_patch_guard';
|
|
531
599
|
const isExecCommandGuard = engineResult.execution.flowId === 'exec_command_guard';
|
|
@@ -570,6 +638,7 @@ export async function runServerToolOrchestration(options) {
|
|
|
570
638
|
};
|
|
571
639
|
}
|
|
572
640
|
const loopState = buildServerToolLoopState(options.adapterContext, engineResult.execution.flowId, followupPayloadRaw, engineResult.finalChatResponse);
|
|
641
|
+
const stopMessageReservation = null;
|
|
573
642
|
if (applyAutoLimit && loopState && typeof loopState.repeatCount === 'number' && loopState.repeatCount >= 3) {
|
|
574
643
|
logProgress(5, totalSteps, 'completed (auto limit hit)', { flowId });
|
|
575
644
|
return {
|
|
@@ -640,9 +709,10 @@ export async function runServerToolOrchestration(options) {
|
|
|
640
709
|
(typeof options.entryEndpoint === 'string' && options.entryEndpoint.trim().length
|
|
641
710
|
? options.entryEndpoint
|
|
642
711
|
: followupEntryEndpoint);
|
|
643
|
-
// For stateful auto-followups (e.g. stop_message_flow / clock_hold_flow),
|
|
712
|
+
// For stateful auto-followups (e.g. stop_message_flow / clock_hold_flow / continue_execution_flow),
|
|
713
|
+
// keep the same providerKey/alias.
|
|
644
714
|
// Otherwise the followup requestId suffix would cause round-robin alias switching and compatibility drift.
|
|
645
|
-
if (isStopMessageFlow || isClockHoldFlow) {
|
|
715
|
+
if (isStopMessageFlow || isClockHoldFlow || isContinueExecutionFlow) {
|
|
646
716
|
const providerKeyRaw = options.adapterContext.providerKey;
|
|
647
717
|
const providerKey = typeof providerKeyRaw === 'string' && providerKeyRaw.trim().length ? providerKeyRaw.trim() : '';
|
|
648
718
|
if (providerKey) {
|
|
@@ -669,7 +739,6 @@ export async function runServerToolOrchestration(options) {
|
|
|
669
739
|
// 否则会出现下一轮仍然自动触发 → 再次失败 → 客户端永远 502 的死循环。
|
|
670
740
|
//
|
|
671
741
|
// stop_message_flow 的计数器递增由 handler 在决定触发时处理,engine 不再提前递增。
|
|
672
|
-
const stopMessageReservation = null;
|
|
673
742
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
674
743
|
const elapsedBeforeAttempt = isStopMessageFlow && loopState && typeof loopState.startedAtMs === 'number' && Number.isFinite(loopState.startedAtMs)
|
|
675
744
|
? Math.max(0, Date.now() - loopState.startedAtMs)
|
|
@@ -687,13 +756,19 @@ export async function runServerToolOrchestration(options) {
|
|
|
687
756
|
const attemptTimeoutMs = isStopMessageFlow && STOP_MESSAGE_STAGE_TIMEOUT_MS > elapsedBeforeAttempt
|
|
688
757
|
? Math.max(1, Math.min(followupTimeoutMs, STOP_MESSAGE_STAGE_TIMEOUT_MS - elapsedBeforeAttempt))
|
|
689
758
|
: followupTimeoutMs;
|
|
759
|
+
const disconnectWatcher = createClientDisconnectWatcher({
|
|
760
|
+
adapterContext: options.adapterContext,
|
|
761
|
+
requestId: options.requestId,
|
|
762
|
+
flowId: engineResult.execution.flowId
|
|
763
|
+
});
|
|
690
764
|
try {
|
|
691
|
-
|
|
765
|
+
const followupPromise = options.reenterPipeline({
|
|
692
766
|
entryEndpoint: followupEntryEndpoint,
|
|
693
767
|
requestId: followupRequestId,
|
|
694
768
|
body: followupPayload,
|
|
695
769
|
metadata
|
|
696
|
-
})
|
|
770
|
+
});
|
|
771
|
+
followup = await withTimeout(Promise.race([followupPromise, disconnectWatcher.promise]), attemptTimeoutMs, () => isStopMessageFlow
|
|
697
772
|
? createStopMessageFetchFailedError({
|
|
698
773
|
requestId: options.requestId,
|
|
699
774
|
reason: 'stage_timeout',
|
|
@@ -710,6 +785,7 @@ export async function runServerToolOrchestration(options) {
|
|
|
710
785
|
attempt,
|
|
711
786
|
maxAttempts
|
|
712
787
|
}));
|
|
788
|
+
disconnectWatcher.cancel();
|
|
713
789
|
// Treat empty followup as failure for auto followup flows:
|
|
714
790
|
// - retry once (maxAttempts=2)
|
|
715
791
|
// - if still empty, surface as HTTP error so client can retry.
|
|
@@ -729,6 +805,15 @@ export async function runServerToolOrchestration(options) {
|
|
|
729
805
|
break;
|
|
730
806
|
}
|
|
731
807
|
catch (error) {
|
|
808
|
+
disconnectWatcher.cancel();
|
|
809
|
+
if (isServerToolClientDisconnectedError(error) || isAdapterClientDisconnected(options.adapterContext)) {
|
|
810
|
+
logProgress(5, totalSteps, 'completed (client disconnected)', { flowId, attempt });
|
|
811
|
+
return {
|
|
812
|
+
chat: engineResult.finalChatResponse,
|
|
813
|
+
executed: true,
|
|
814
|
+
flowId: engineResult.execution.flowId
|
|
815
|
+
};
|
|
816
|
+
}
|
|
732
817
|
if (isServerToolTimeoutError(error)) {
|
|
733
818
|
throw error;
|
|
734
819
|
}
|
|
@@ -755,28 +840,30 @@ export async function runServerToolOrchestration(options) {
|
|
|
755
840
|
: undefined;
|
|
756
841
|
if (retryEmptyFollowupOnce && (!followupBody || isEmptyClientResponsePayload(followupBody))) {
|
|
757
842
|
if (isStopMessageFlow) {
|
|
758
|
-
// 对 stopMessage
|
|
759
|
-
//
|
|
843
|
+
// 对 stopMessage:先清理状态,避免后续请求继续触发失败循环;
|
|
844
|
+
// 若原始响应可用则回退原始响应,否则显式抛错,避免“静默空响应”。
|
|
760
845
|
disableStopMessageAfterFailedFollowup(options.adapterContext, stopMessageReservation);
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
details: {
|
|
846
|
+
const fallbackOriginal = engineResult.finalChatResponse;
|
|
847
|
+
if (fallbackOriginal && !isEmptyClientResponsePayload(fallbackOriginal)) {
|
|
848
|
+
logProgress(5, totalSteps, 'completed (stopMessage followup empty; fallback to original)', { flowId });
|
|
849
|
+
return {
|
|
850
|
+
chat: fallbackOriginal,
|
|
851
|
+
executed: true,
|
|
852
|
+
flowId: engineResult.execution.flowId
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
throw createEmptyFollowupError({
|
|
772
856
|
flowId: engineResult.execution.flowId,
|
|
773
857
|
requestId: options.requestId,
|
|
774
|
-
|
|
775
|
-
|
|
858
|
+
lastError,
|
|
859
|
+
originalResponseWasEmpty: true
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
throw createEmptyFollowupError({
|
|
863
|
+
flowId: engineResult.execution.flowId,
|
|
864
|
+
requestId: options.requestId,
|
|
865
|
+
lastError
|
|
776
866
|
});
|
|
777
|
-
wrapped.status = 502;
|
|
778
|
-
wrapped.cause = lastError;
|
|
779
|
-
throw wrapped;
|
|
780
867
|
}
|
|
781
868
|
// Special case: Antigravity thoughtSignature bootstrap flow.
|
|
782
869
|
// - First followup performs a minimal preflight (forces clock.get) to obtain a fresh signature.
|
|
@@ -899,19 +986,78 @@ function resolveStickyKeyFromAdapterContext(adapterContext) {
|
|
|
899
986
|
if (!adapterContext || typeof adapterContext !== 'object') {
|
|
900
987
|
return undefined;
|
|
901
988
|
}
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
989
|
+
const record = adapterContext;
|
|
990
|
+
const runtime = readRuntimeMetadata(record);
|
|
991
|
+
const providerProtocol = readTextFromAny(record.providerProtocol) ||
|
|
992
|
+
readTextFromAny(runtime?.providerProtocol) ||
|
|
993
|
+
readTextFromAny(record.provider_protocol) ||
|
|
994
|
+
readTextFromAny(runtime?.provider_protocol);
|
|
995
|
+
if (providerProtocol.trim().toLowerCase() === 'openai-responses') {
|
|
996
|
+
const previousRequestId = resolveResponsesResumePreviousRequestId(record, runtime);
|
|
997
|
+
if (previousRequestId) {
|
|
998
|
+
return previousRequestId;
|
|
999
|
+
}
|
|
1000
|
+
const requestId = resolveStickyRequestId(record, runtime);
|
|
1001
|
+
if (requestId) {
|
|
1002
|
+
return requestId;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
const sessionId = readTextFromAny(record.sessionId) ||
|
|
1006
|
+
readTextFromAny(record.session_id) ||
|
|
1007
|
+
readTextFromAny(runtime?.sessionId) ||
|
|
1008
|
+
readTextFromAny(runtime?.session_id);
|
|
1009
|
+
const conversationId = readTextFromAny(record.conversationId) ||
|
|
1010
|
+
readTextFromAny(record.conversation_id) ||
|
|
1011
|
+
readTextFromAny(runtime?.conversationId) ||
|
|
1012
|
+
readTextFromAny(runtime?.conversation_id);
|
|
908
1013
|
if (sessionId) {
|
|
909
1014
|
return `session:${sessionId}`;
|
|
910
1015
|
}
|
|
911
1016
|
if (conversationId) {
|
|
912
1017
|
return `conversation:${conversationId}`;
|
|
913
1018
|
}
|
|
914
|
-
|
|
1019
|
+
const requestId = resolveStickyRequestId(record, runtime);
|
|
1020
|
+
return requestId || undefined;
|
|
1021
|
+
}
|
|
1022
|
+
function resolveStickyRequestId(context, runtime) {
|
|
1023
|
+
return (readTextFromAny(context.requestId) ||
|
|
1024
|
+
readTextFromAny(context.request_id) ||
|
|
1025
|
+
readTextFromAny(runtime?.requestId) ||
|
|
1026
|
+
readTextFromAny(runtime?.request_id));
|
|
1027
|
+
}
|
|
1028
|
+
function resolveResponsesResumePreviousRequestId(context, runtime) {
|
|
1029
|
+
const contextMetadata = asRecord(context.metadata);
|
|
1030
|
+
const contextMetadataContext = asRecord(contextMetadata?.context);
|
|
1031
|
+
const originalRequest = asRecord(context.originalRequest);
|
|
1032
|
+
const originalMetadata = asRecord(originalRequest?.metadata);
|
|
1033
|
+
const candidates = [
|
|
1034
|
+
context.responsesResume,
|
|
1035
|
+
contextMetadata?.responsesResume,
|
|
1036
|
+
contextMetadataContext?.responsesResume,
|
|
1037
|
+
originalRequest?.responsesResume,
|
|
1038
|
+
originalMetadata?.responsesResume,
|
|
1039
|
+
runtime?.responsesResume
|
|
1040
|
+
];
|
|
1041
|
+
for (const candidate of candidates) {
|
|
1042
|
+
const resume = asRecord(candidate);
|
|
1043
|
+
if (!resume) {
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
const previousRequestId = readTextFromAny(resume.previousRequestId) || readTextFromAny(resume.previous_request_id);
|
|
1047
|
+
if (previousRequestId) {
|
|
1048
|
+
return previousRequestId;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return '';
|
|
1052
|
+
}
|
|
1053
|
+
function asRecord(value) {
|
|
1054
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
return value;
|
|
1058
|
+
}
|
|
1059
|
+
function readTextFromAny(value) {
|
|
1060
|
+
return typeof value === 'string' && value.trim().length ? value.trim() : '';
|
|
915
1061
|
}
|
|
916
1062
|
function cloneRoutingInstructionState(state) {
|
|
917
1063
|
if (!state) {
|
|
@@ -4,6 +4,7 @@ import { readRuntimeMetadata } from '../../conversion/shared/runtime-metadata.js
|
|
|
4
4
|
import { findNextUndeliveredDueAtMs, listClockTasks, reserveDueTasksForRequest, resolveClockConfig, startClockDaemonIfNeeded } from '../clock/task-store.js';
|
|
5
5
|
import { nowMs } from '../clock/state.js';
|
|
6
6
|
import { logClock } from '../clock/log.js';
|
|
7
|
+
import { resolveClockSessionScope } from '../clock/session-scope.js';
|
|
7
8
|
import { isStopEligibleForServerTool } from '../stop-gateway-context.js';
|
|
8
9
|
const FLOW_ID = 'clock_hold_flow';
|
|
9
10
|
function resolveClientConnectionState(value) {
|
|
@@ -40,13 +41,6 @@ function clientWantsStreaming(adapterContext) {
|
|
|
40
41
|
}
|
|
41
42
|
return false;
|
|
42
43
|
}
|
|
43
|
-
function resolveSessionId(adapterContext) {
|
|
44
|
-
if (!adapterContext || typeof adapterContext !== 'object' || Array.isArray(adapterContext)) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
const sessionId = typeof adapterContext.sessionId === 'string' ? String(adapterContext.sessionId).trim() : '';
|
|
48
|
-
return sessionId || null;
|
|
49
|
-
}
|
|
50
44
|
function computeHoldSleepMs(remainingMs) {
|
|
51
45
|
if (remainingMs <= 0)
|
|
52
46
|
return 0;
|
|
@@ -81,7 +75,7 @@ const handler = async (ctx) => {
|
|
|
81
75
|
return null;
|
|
82
76
|
}
|
|
83
77
|
const rt = readRuntimeMetadata(ctx.adapterContext);
|
|
84
|
-
const sessionId =
|
|
78
|
+
const sessionId = resolveClockSessionScope(ctx.adapterContext, rt);
|
|
85
79
|
if (!sessionId) {
|
|
86
80
|
return null;
|
|
87
81
|
}
|