@jsonstudio/llms 0.6.1449 → 0.6.1643
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/codecs/gemini-openai-codec.js +6 -1
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +4 -6
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +179 -41
- package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +73 -14
- package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +165 -10
- package/dist/conversion/compat/actions/gemini-cli-request.js +72 -13
- package/dist/conversion/compat/antigravity-session-signature.d.ts +68 -1
- package/dist/conversion/compat/antigravity-session-signature.js +833 -21
- package/dist/conversion/compat/profiles/anthropic-claude-code.json +17 -0
- package/dist/conversion/compat/profiles/chat-gemini-cli.json +1 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +33 -8
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +17 -1
- package/dist/conversion/hub/pipeline/compat/compat-profile-store.js +12 -3
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +24 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +20 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +26 -1
- package/dist/conversion/hub/process/chat-process.js +300 -67
- package/dist/conversion/hub/response/provider-response.js +4 -3
- package/dist/conversion/shared/gemini-tool-utils.js +134 -9
- package/dist/conversion/shared/text-markup-normalizer.js +90 -1
- package/dist/conversion/shared/thought-signature-validator.d.ts +1 -1
- package/dist/conversion/shared/thought-signature-validator.js +2 -1
- package/dist/quota/apikey-reset.d.ts +17 -0
- package/dist/quota/apikey-reset.js +43 -0
- package/dist/quota/index.d.ts +2 -0
- package/dist/quota/index.js +1 -0
- package/dist/quota/quota-manager.d.ts +44 -0
- package/dist/quota/quota-manager.js +491 -0
- package/dist/quota/quota-state.d.ts +6 -0
- package/dist/quota/quota-state.js +167 -0
- package/dist/quota/types.d.ts +61 -0
- package/dist/quota/types.js +1 -0
- package/dist/router/virtual-router/bootstrap.js +103 -6
- package/dist/router/virtual-router/engine-health.js +104 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +18 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +1 -2
- package/dist/router/virtual-router/engine-selection/tier-priority.js +2 -2
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +34 -10
- package/dist/router/virtual-router/engine-selection/tier-selection.js +250 -6
- package/dist/router/virtual-router/engine-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +16 -1
- package/dist/router/virtual-router/engine.js +320 -42
- package/dist/router/virtual-router/features.js +20 -2
- package/dist/router/virtual-router/success-center.d.ts +10 -0
- package/dist/router/virtual-router/success-center.js +32 -0
- package/dist/router/virtual-router/types.d.ts +48 -0
- package/dist/servertool/clock/config.d.ts +2 -0
- package/dist/servertool/clock/config.js +10 -2
- package/dist/servertool/clock/daemon.js +3 -0
- package/dist/servertool/clock/ntp.d.ts +18 -0
- package/dist/servertool/clock/ntp.js +318 -0
- package/dist/servertool/clock/paths.d.ts +1 -0
- package/dist/servertool/clock/paths.js +3 -0
- package/dist/servertool/clock/state.d.ts +2 -0
- package/dist/servertool/clock/state.js +15 -2
- package/dist/servertool/clock/tasks.d.ts +1 -0
- package/dist/servertool/clock/tasks.js +24 -1
- package/dist/servertool/clock/types.d.ts +21 -0
- package/dist/servertool/engine.js +105 -1
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.d.ts +1 -0
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +201 -0
- package/dist/servertool/handlers/clock-auto.js +39 -4
- package/dist/servertool/handlers/clock.js +145 -16
- package/dist/servertool/handlers/followup-request-builder.js +84 -0
- package/dist/servertool/handlers/stop-message-auto.js +1 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +1 -0
- package/dist/servertool/types.d.ts +2 -0
- package/dist/tools/apply-patch/execution-capturer.js +24 -3
- package/package.json +3 -2
|
@@ -3,8 +3,10 @@ import { ToolGovernanceEngine } from '../tool-governance/index.js';
|
|
|
3
3
|
import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
|
|
4
4
|
import { ensureApplyPatchSchema } from '../../shared/tool-mapping.js';
|
|
5
5
|
import { normalizeApplyPatchToolCallsOnRequest } from '../../shared/tool-governor.js';
|
|
6
|
+
import { buildAnthropicToolAliasMap } from '../../shared/anthropic-message-utils.js';
|
|
6
7
|
import { clearClockSession, resolveClockConfig, reserveDueTasksForRequest, startClockDaemonIfNeeded } from '../../../servertool/clock/task-store.js';
|
|
7
8
|
import { logClock } from '../../../servertool/clock/log.js';
|
|
9
|
+
import { buildTimeTagLine, getClockTimeSnapshot } from '../../../servertool/clock/ntp.js';
|
|
8
10
|
import { clearPendingServerToolInjection, loadPendingServerToolInjection } from '../../../servertool/pending-session.js';
|
|
9
11
|
import { isJsonObject } from '../types/json.js';
|
|
10
12
|
import { applyHubOperations } from '../ops/operations.js';
|
|
@@ -38,6 +40,35 @@ async function applyRequestToolGovernance(request, context) {
|
|
|
38
40
|
const metadataToolHints = metadata.toolFilterHints;
|
|
39
41
|
const metadataStreamFlag = metadata.stream;
|
|
40
42
|
const inboundStreamIntent = typeof metadataStreamFlag === 'boolean' ? metadataStreamFlag : request.parameters?.stream === true;
|
|
43
|
+
// /v1/messages: preserve the caller's tool naming (Bash/Glob/Read, etc.) so we can
|
|
44
|
+
// remap tool calls back to the client protocol shape after routing through providers
|
|
45
|
+
// that canonicalize tool names (e.g. OpenAI function names lowercased).
|
|
46
|
+
//
|
|
47
|
+
// NOTE: This is mappable semantics and must live in request.semantics (never metadata).
|
|
48
|
+
try {
|
|
49
|
+
if (entryEndpoint.toLowerCase().includes('/v1/messages')) {
|
|
50
|
+
request.semantics = request.semantics && typeof request.semantics === 'object' && !Array.isArray(request.semantics)
|
|
51
|
+
? request.semantics
|
|
52
|
+
: {};
|
|
53
|
+
const semanticsTools = request.semantics.tools && typeof request.semantics.tools === 'object' && !Array.isArray(request.semantics.tools)
|
|
54
|
+
? request.semantics.tools
|
|
55
|
+
: (request.semantics.tools = {});
|
|
56
|
+
const hasAlias = isJsonObject(semanticsTools.toolNameAliasMap) ||
|
|
57
|
+
isJsonObject(semanticsTools.toolAliasMap);
|
|
58
|
+
if (!hasAlias) {
|
|
59
|
+
const sourceTools = Array.isArray(semanticsTools.clientToolsRaw) && semanticsTools.clientToolsRaw.length
|
|
60
|
+
? semanticsTools.clientToolsRaw
|
|
61
|
+
: request.tools;
|
|
62
|
+
const aliasMap = buildAnthropicToolAliasMap(sourceTools);
|
|
63
|
+
if (aliasMap) {
|
|
64
|
+
semanticsTools.toolNameAliasMap = aliasMap;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// best-effort: never block request handling due to alias map propagation failures
|
|
71
|
+
}
|
|
41
72
|
const shaped = {
|
|
42
73
|
model: request.model,
|
|
43
74
|
messages: deepClone(request.messages),
|
|
@@ -287,23 +318,31 @@ function stripHistoricalImageAttachments(messages) {
|
|
|
287
318
|
if (!Array.isArray(messages) || !messages.length) {
|
|
288
319
|
return messages;
|
|
289
320
|
}
|
|
290
|
-
|
|
291
|
-
|
|
321
|
+
const placeholderText = '[Image omitted]';
|
|
322
|
+
const last = messages[messages.length - 1];
|
|
323
|
+
const lastRole = typeof last?.role === 'string' ? String(last.role) : '';
|
|
324
|
+
const isNewUserTurn = lastRole === 'user';
|
|
325
|
+
// 找到最新一条 user 消息:
|
|
326
|
+
// - 若本轮是 user 输入(最后一条消息 role=user),则仅允许这一条保留图片分段;
|
|
327
|
+
// - 若本轮是 followup(最后一条消息非 user,例如 tool/assistant),则所有 user 消息的图片都应替换为占位符,
|
|
328
|
+
// 避免在工具循环/多次 followup 中反复透传大体积图片数据。
|
|
292
329
|
let latestUserIndex = -1;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
330
|
+
if (isNewUserTurn) {
|
|
331
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
332
|
+
const candidate = messages[idx];
|
|
333
|
+
if (candidate && typeof candidate === 'object' && candidate.role === 'user') {
|
|
334
|
+
latestUserIndex = idx;
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (latestUserIndex < 0) {
|
|
339
|
+
return messages;
|
|
298
340
|
}
|
|
299
|
-
}
|
|
300
|
-
if (latestUserIndex < 0) {
|
|
301
|
-
return messages;
|
|
302
341
|
}
|
|
303
342
|
let changed = false;
|
|
304
343
|
const next = messages.slice();
|
|
305
344
|
for (let idx = 0; idx < messages.length; idx += 1) {
|
|
306
|
-
if (idx === latestUserIndex) {
|
|
345
|
+
if (isNewUserTurn && idx === latestUserIndex) {
|
|
307
346
|
continue;
|
|
308
347
|
}
|
|
309
348
|
const message = messages[idx];
|
|
@@ -324,6 +363,7 @@ function stripHistoricalImageAttachments(messages) {
|
|
|
324
363
|
const typeValue = part.type;
|
|
325
364
|
if (typeof typeValue === 'string' && typeValue.toLowerCase().includes('image')) {
|
|
326
365
|
removed = true;
|
|
366
|
+
filtered.push({ type: 'text', text: placeholderText });
|
|
327
367
|
continue;
|
|
328
368
|
}
|
|
329
369
|
}
|
|
@@ -344,19 +384,13 @@ function containsImageAttachment(messages) {
|
|
|
344
384
|
if (!Array.isArray(messages) || !messages.length) {
|
|
345
385
|
return false;
|
|
346
386
|
}
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (candidate && typeof candidate === 'object' && candidate.role === 'user') {
|
|
352
|
-
latestUser = candidate;
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (!latestUser) {
|
|
387
|
+
// 仅检查“当前这一轮用户输入”(messages 最后一条必须是 user)是否携带图片。
|
|
388
|
+
// 避免在 tool/assistant followup 请求中,因为历史 user 消息含图片而反复触发 image 标记。
|
|
389
|
+
const last = messages[messages.length - 1];
|
|
390
|
+
if (!last || typeof last !== 'object' || Array.isArray(last) || last.role !== 'user') {
|
|
357
391
|
return false;
|
|
358
392
|
}
|
|
359
|
-
const content =
|
|
393
|
+
const content = last.content;
|
|
360
394
|
if (!Array.isArray(content)) {
|
|
361
395
|
return false;
|
|
362
396
|
}
|
|
@@ -628,8 +662,8 @@ function buildClockOperations(metadata) {
|
|
|
628
662
|
properties: {
|
|
629
663
|
action: {
|
|
630
664
|
type: 'string',
|
|
631
|
-
enum: ['schedule', 'list', 'cancel', 'clear'],
|
|
632
|
-
description: '
|
|
665
|
+
enum: ['get', 'schedule', 'list', 'cancel', 'clear'],
|
|
666
|
+
description: 'Get current time, or schedule/list/cancel/clear session-scoped reminders.'
|
|
633
667
|
},
|
|
634
668
|
items: {
|
|
635
669
|
type: 'array',
|
|
@@ -674,7 +708,7 @@ function buildClockOperations(metadata) {
|
|
|
674
708
|
type: 'function',
|
|
675
709
|
function: {
|
|
676
710
|
name: 'clock',
|
|
677
|
-
description: '
|
|
711
|
+
description: 'Time + Alarm for this session. Use get/schedule/list/cancel/clear. Scheduled reminders will be injected into future requests.',
|
|
678
712
|
parameters,
|
|
679
713
|
strict: true
|
|
680
714
|
}
|
|
@@ -766,14 +800,14 @@ async function maybeInjectClockRemindersAndApplyDirectives(request, metadata, re
|
|
|
766
800
|
const lastUserIdx = findLastUserMessageIndex(messages);
|
|
767
801
|
// 1) Apply <**clock:clear**> directive (latest user message only).
|
|
768
802
|
let hadClear = false;
|
|
769
|
-
let
|
|
803
|
+
let baseMessages = messages;
|
|
770
804
|
if (lastUserIdx >= 0) {
|
|
771
805
|
const lastUser = messages[lastUserIdx];
|
|
772
806
|
const stripped = stripClockClearDirectiveFromContent(lastUser.content);
|
|
773
807
|
hadClear = stripped.hadClear;
|
|
774
808
|
if (hadClear) {
|
|
775
|
-
|
|
776
|
-
|
|
809
|
+
baseMessages = messages.slice();
|
|
810
|
+
baseMessages[lastUserIdx] = { ...lastUser, content: stripped.next };
|
|
777
811
|
}
|
|
778
812
|
}
|
|
779
813
|
if (hadClear) {
|
|
@@ -786,50 +820,249 @@ async function maybeInjectClockRemindersAndApplyDirectives(request, metadata, re
|
|
|
786
820
|
// best-effort: user directive should not crash request
|
|
787
821
|
}
|
|
788
822
|
}
|
|
789
|
-
|
|
790
|
-
}
|
|
791
|
-
// 2) Inject due reminders as a
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
823
|
+
// Continue: still inject per-request time tag (but skip due reminders).
|
|
824
|
+
}
|
|
825
|
+
// 2) Inject due reminders as a user message + attach reservation for response-side commit.
|
|
826
|
+
let reservation = null;
|
|
827
|
+
let dueInjectText = '';
|
|
828
|
+
if (!hadClear && sessionId) {
|
|
829
|
+
try {
|
|
830
|
+
const reserved = await reserveDueTasksForRequest({
|
|
831
|
+
reservationId: `${requestId}:clock`,
|
|
832
|
+
sessionId,
|
|
833
|
+
config: clockConfig,
|
|
834
|
+
requestId
|
|
835
|
+
});
|
|
836
|
+
reservation = reserved.reservation;
|
|
837
|
+
dueInjectText = typeof reserved.injectText === 'string' ? reserved.injectText.trim() : '';
|
|
803
838
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
};
|
|
839
|
+
catch {
|
|
840
|
+
// best-effort
|
|
841
|
+
reservation = null;
|
|
842
|
+
dueInjectText = '';
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const dueUserMessage = (() => {
|
|
846
|
+
if (!reservation || !dueInjectText)
|
|
847
|
+
return null;
|
|
814
848
|
return {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
],
|
|
823
|
-
metadata: {
|
|
824
|
-
...baseMetadata,
|
|
825
|
-
__clockReservation: reservation
|
|
826
|
-
}
|
|
849
|
+
role: 'user',
|
|
850
|
+
content: [
|
|
851
|
+
'[Clock Reminder]: scheduled tasks are due.',
|
|
852
|
+
dueInjectText,
|
|
853
|
+
'You may call tools to complete these tasks. If the tool list is incomplete, standard tools have been injected.'
|
|
854
|
+
].join('\n')
|
|
827
855
|
};
|
|
856
|
+
})();
|
|
857
|
+
// 3) When we have due tasks, ensure a standard tool set is present (best-effort).
|
|
858
|
+
let nextRequest = request;
|
|
859
|
+
if (dueUserMessage) {
|
|
860
|
+
const ensureToolsOps = buildClockStandardToolsOperations();
|
|
861
|
+
nextRequest = applyHubOperations(nextRequest, ensureToolsOps);
|
|
862
|
+
}
|
|
863
|
+
// 4) Per-request time injection (user time tag or paired clock.get tool result).
|
|
864
|
+
let snapshot = null;
|
|
865
|
+
try {
|
|
866
|
+
snapshot = await getClockTimeSnapshot();
|
|
828
867
|
}
|
|
829
868
|
catch {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
869
|
+
snapshot = null;
|
|
870
|
+
}
|
|
871
|
+
const timeTagLine = snapshot
|
|
872
|
+
? buildTimeTagLine(snapshot)
|
|
873
|
+
: '[Time/Date]: utc=`1970-01-01T00:00:00.000Z` local=`1970-01-01 00:00:00.000 +00:00` tz=`unknown` nowMs=`0` ntpOffsetMs=`0`';
|
|
874
|
+
const baseMetadata = nextRequest.metadata && typeof nextRequest.metadata === 'object'
|
|
875
|
+
? nextRequest.metadata
|
|
876
|
+
: {
|
|
877
|
+
originalEndpoint: readString(metadata.originalEndpoint) ?? '/v1/chat/completions'
|
|
878
|
+
};
|
|
879
|
+
const withReservationMetadata = dueUserMessage && reservation
|
|
880
|
+
? {
|
|
881
|
+
...baseMetadata,
|
|
882
|
+
__clockReservation: reservation
|
|
883
|
+
}
|
|
884
|
+
: baseMetadata;
|
|
885
|
+
const messagesWithDue = dueUserMessage ? [...baseMessages, dueUserMessage] : baseMessages.slice();
|
|
886
|
+
// Always inject time via user-role content to keep the tag visible without adding
|
|
887
|
+
// extra tool-call semantics that may distract the model.
|
|
888
|
+
//
|
|
889
|
+
// IMPORTANT: do not append an extra trailing user message, otherwise the Virtual Router
|
|
890
|
+
// sees `latestMessageFromUser=true` and will force "thinking:user-input" even during
|
|
891
|
+
// tool followups (last message role=tool), which breaks `coding/search/tools` routing.
|
|
892
|
+
const timeInjectedMessages = (() => {
|
|
893
|
+
const idx = findLastUserMessageIndex(messagesWithDue);
|
|
894
|
+
if (idx < 0) {
|
|
895
|
+
return [...messagesWithDue, { role: 'user', content: timeTagLine }];
|
|
896
|
+
}
|
|
897
|
+
const msg = messagesWithDue[idx];
|
|
898
|
+
const content = msg.content;
|
|
899
|
+
const nextContent = (() => {
|
|
900
|
+
if (typeof content === 'string') {
|
|
901
|
+
const base = content.trimEnd();
|
|
902
|
+
return base ? `${base}\n${timeTagLine}` : timeTagLine;
|
|
903
|
+
}
|
|
904
|
+
if (Array.isArray(content)) {
|
|
905
|
+
return [...content, timeTagLine];
|
|
906
|
+
}
|
|
907
|
+
return timeTagLine;
|
|
908
|
+
})();
|
|
909
|
+
const cloned = messagesWithDue.slice();
|
|
910
|
+
cloned[idx] = { ...msg, content: nextContent };
|
|
911
|
+
return cloned;
|
|
912
|
+
})();
|
|
913
|
+
return {
|
|
914
|
+
...nextRequest,
|
|
915
|
+
messages: timeInjectedMessages,
|
|
916
|
+
metadata: withReservationMetadata
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
function buildClockStandardToolsOperations() {
|
|
920
|
+
const tools = [
|
|
921
|
+
{
|
|
922
|
+
type: 'function',
|
|
923
|
+
function: {
|
|
924
|
+
name: 'shell',
|
|
925
|
+
description: 'Runs a shell command and returns its output.',
|
|
926
|
+
parameters: {
|
|
927
|
+
type: 'object',
|
|
928
|
+
properties: {
|
|
929
|
+
command: { oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }] },
|
|
930
|
+
workdir: { type: 'string' }
|
|
931
|
+
},
|
|
932
|
+
required: ['command'],
|
|
933
|
+
additionalProperties: false
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
type: 'function',
|
|
939
|
+
function: {
|
|
940
|
+
name: 'exec_command',
|
|
941
|
+
description: 'Execute a command in a PTY and return output.',
|
|
942
|
+
parameters: {
|
|
943
|
+
type: 'object',
|
|
944
|
+
properties: {
|
|
945
|
+
cmd: { type: 'string' },
|
|
946
|
+
workdir: { type: 'string' },
|
|
947
|
+
timeout_ms: { type: 'number' },
|
|
948
|
+
max_output_tokens: { type: 'number' },
|
|
949
|
+
yield_time_ms: { type: 'number' }
|
|
950
|
+
},
|
|
951
|
+
required: ['cmd'],
|
|
952
|
+
additionalProperties: false
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
type: 'function',
|
|
958
|
+
function: {
|
|
959
|
+
name: 'apply_patch',
|
|
960
|
+
description: 'Apply a patch to repository files.',
|
|
961
|
+
parameters: {
|
|
962
|
+
type: 'object',
|
|
963
|
+
properties: {
|
|
964
|
+
patch: { type: 'string' }
|
|
965
|
+
},
|
|
966
|
+
required: ['patch'],
|
|
967
|
+
additionalProperties: false
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
type: 'function',
|
|
973
|
+
function: {
|
|
974
|
+
name: 'update_plan',
|
|
975
|
+
description: 'Update the task plan.',
|
|
976
|
+
parameters: {
|
|
977
|
+
type: 'object',
|
|
978
|
+
properties: {
|
|
979
|
+
explanation: { type: 'string' },
|
|
980
|
+
plan: {
|
|
981
|
+
type: 'array',
|
|
982
|
+
items: {
|
|
983
|
+
type: 'object',
|
|
984
|
+
properties: {
|
|
985
|
+
step: { type: 'string' },
|
|
986
|
+
status: { type: 'string' }
|
|
987
|
+
},
|
|
988
|
+
required: ['step', 'status'],
|
|
989
|
+
additionalProperties: false
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
required: ['plan'],
|
|
994
|
+
additionalProperties: false
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
type: 'function',
|
|
1000
|
+
function: {
|
|
1001
|
+
name: 'view_image',
|
|
1002
|
+
description: 'View a local image by file path.',
|
|
1003
|
+
parameters: {
|
|
1004
|
+
type: 'object',
|
|
1005
|
+
properties: {
|
|
1006
|
+
path: { type: 'string' }
|
|
1007
|
+
},
|
|
1008
|
+
required: ['path'],
|
|
1009
|
+
additionalProperties: false
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
type: 'function',
|
|
1015
|
+
function: {
|
|
1016
|
+
name: 'list_mcp_resources',
|
|
1017
|
+
description: 'List resources exposed by MCP servers.',
|
|
1018
|
+
parameters: {
|
|
1019
|
+
type: 'object',
|
|
1020
|
+
properties: {
|
|
1021
|
+
server: { type: 'string' },
|
|
1022
|
+
filter: { type: 'string' },
|
|
1023
|
+
root: { type: 'string' }
|
|
1024
|
+
},
|
|
1025
|
+
additionalProperties: false
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
type: 'function',
|
|
1031
|
+
function: {
|
|
1032
|
+
name: 'list_mcp_resource_templates',
|
|
1033
|
+
description: 'List resource templates exposed by MCP servers.',
|
|
1034
|
+
parameters: {
|
|
1035
|
+
type: 'object',
|
|
1036
|
+
properties: {
|
|
1037
|
+
server: { type: 'string' },
|
|
1038
|
+
cursor: { type: 'string' }
|
|
1039
|
+
},
|
|
1040
|
+
additionalProperties: false
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
type: 'function',
|
|
1046
|
+
function: {
|
|
1047
|
+
name: 'read_mcp_resource',
|
|
1048
|
+
description: 'Read a specific MCP resource by { server, uri }.',
|
|
1049
|
+
parameters: {
|
|
1050
|
+
type: 'object',
|
|
1051
|
+
properties: {
|
|
1052
|
+
server: { type: 'string' },
|
|
1053
|
+
uri: { type: 'string' }
|
|
1054
|
+
},
|
|
1055
|
+
required: ['server', 'uri'],
|
|
1056
|
+
additionalProperties: false
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
];
|
|
1061
|
+
return tools.map((tool) => ({
|
|
1062
|
+
op: 'append_tool_if_missing',
|
|
1063
|
+
toolName: tool.function.name,
|
|
1064
|
+
tool
|
|
1065
|
+
}));
|
|
833
1066
|
}
|
|
834
1067
|
function extractWebSearchSemantics(semantics) {
|
|
835
1068
|
if (!semantics || typeof semantics !== 'object') {
|
|
@@ -17,7 +17,7 @@ import { recordResponsesResponse } from '../../shared/responses-conversation-sto
|
|
|
17
17
|
import { ProviderProtocolError } from '../../shared/errors.js';
|
|
18
18
|
import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
|
|
19
19
|
import { runServerToolOrchestration } from '../../../servertool/engine.js';
|
|
20
|
-
import { commitClockReservation,
|
|
20
|
+
import { commitClockReservation, resolveClockConfig } from '../../../servertool/clock/task-store.js';
|
|
21
21
|
const PROVIDER_RESPONSE_REGISTRY = {
|
|
22
22
|
'openai-chat': {
|
|
23
23
|
createFormatAdapter: () => new ChatFormatAdapter(),
|
|
@@ -89,7 +89,7 @@ function coerceClockReservation(value) {
|
|
|
89
89
|
async function maybeCommitClockReservationFromContext(context) {
|
|
90
90
|
try {
|
|
91
91
|
const rt = readRuntimeMetadata(context);
|
|
92
|
-
const clockConfig =
|
|
92
|
+
const clockConfig = resolveClockConfig(rt?.clock);
|
|
93
93
|
if (!clockConfig) {
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -269,8 +269,9 @@ export async function convertProviderResponse(options) {
|
|
|
269
269
|
? String(loopState.flowId || '').trim()
|
|
270
270
|
: '';
|
|
271
271
|
const isStopMessageFlow = flowId === 'stop_message_flow';
|
|
272
|
+
const allowNestedServerTools = isStopMessageFlow || flowId === 'antigravity_thought_signature_bootstrap';
|
|
272
273
|
// stop_message_flow 的 followup 允许再次触发(直到 maxRepeats),其他 followup 跳过。
|
|
273
|
-
const skipServerTools = (isFollowup && !
|
|
274
|
+
const skipServerTools = (isFollowup && !allowNestedServerTools) || !hasServerToolSupport;
|
|
274
275
|
// 对于由 server-side 工具触发的内部跳转(二跳/三跳),统一禁用 SSE 聚合输出,
|
|
275
276
|
// 始终返回完整的 ChatCompletion JSON,便于在 llms 内部直接解析,而不是拿到
|
|
276
277
|
// __sse_responses 可读流。
|