@myagentroam/agent 0.10.8 → 0.10.10
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/agent-core/model/anthropic-messages.js +5 -21
- package/dist/agent-core/model/catalog-file.d.ts +14 -0
- package/dist/agent-core/model/configuration.d.ts +7 -0
- package/dist/agent-core/model/configuration.js +10 -0
- package/dist/agent-core/model/openai-responses.d.ts +1 -1
- package/dist/agent-core/model/openai-responses.js +61 -29
- package/dist/agent-core/model/runtime-credential.d.ts +2 -0
- package/dist/agent-core/model/runtime-credential.js +15 -0
- package/dist/agent-core/model/sse.d.ts +1 -1
- package/dist/agent-core/model/sse.js +22 -4
- package/dist/agent-core/model/tool-input.d.ts +3 -0
- package/dist/agent-core/model/tool-input.js +18 -0
- package/dist/agent-core/runtime/model-generation-timing.js +1 -1
- package/dist/agent-core/tools/code-mode/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { observeModelRequestUsage } from './usage-observer.js';
|
|
2
|
+
import { jsonToolInput } from './tool-input.js';
|
|
2
3
|
import { observationModelParts } from '../tools/code-mode/observations.js';
|
|
3
4
|
import { stableToolSchema } from '../tools/definition-projection.js';
|
|
4
5
|
import { randomUUID } from 'node:crypto';
|
|
@@ -144,7 +145,7 @@ export class AnthropicMessagesAdapter {
|
|
|
144
145
|
let terminal;
|
|
145
146
|
let latestInputUsage;
|
|
146
147
|
let thinkingBytes = 0;
|
|
147
|
-
for await (const raw of parseAnthropicSse(response, signal)) {
|
|
148
|
+
for await (const raw of parseAnthropicSse(response, signal, apiKey.reveal())) {
|
|
148
149
|
const event = record(raw);
|
|
149
150
|
const type = text(event.type) ?? 'unknown';
|
|
150
151
|
const index = number(event.index) ?? -1;
|
|
@@ -424,9 +425,9 @@ export class AnthropicMessagesAdapter {
|
|
|
424
425
|
});
|
|
425
426
|
}
|
|
426
427
|
}
|
|
427
|
-
async function* parseAnthropicSse(response, signal) {
|
|
428
|
+
async function* parseAnthropicSse(response, signal, apiKey) {
|
|
428
429
|
try {
|
|
429
|
-
yield* parseSse(response, signal);
|
|
430
|
+
yield* parseSse(response, signal, undefined, undefined, [apiKey]);
|
|
430
431
|
}
|
|
431
432
|
catch (cause) {
|
|
432
433
|
if (response.ok &&
|
|
@@ -551,7 +552,7 @@ function anthropicMessages(messages, images, tools = [], modelId, automaticCache
|
|
|
551
552
|
type: 'tool_use',
|
|
552
553
|
id: message.callId,
|
|
553
554
|
name: message.name,
|
|
554
|
-
input:
|
|
555
|
+
input: jsonToolInput(message, toolDefinitions.get(message.name ?? ''))
|
|
555
556
|
};
|
|
556
557
|
const previous = result.at(-1);
|
|
557
558
|
if (previous?.role === 'assistant' && Array.isArray(previous.content))
|
|
@@ -673,23 +674,6 @@ function uniqueModelImages(...groups) {
|
|
|
673
674
|
return [image];
|
|
674
675
|
}));
|
|
675
676
|
}
|
|
676
|
-
function anthropicToolInput(message, tool) {
|
|
677
|
-
if (isObject(message.arguments))
|
|
678
|
-
return message.arguments;
|
|
679
|
-
if (message.inputMode !== 'freeform')
|
|
680
|
-
return {};
|
|
681
|
-
const property = freeformInputProperty(tool?.inputSchema);
|
|
682
|
-
return { [property ?? 'input']: String(message.arguments ?? '') };
|
|
683
|
-
}
|
|
684
|
-
function freeformInputProperty(schema) {
|
|
685
|
-
if (schema?.type !== 'object' || !isObject(schema.properties) || !Array.isArray(schema.required))
|
|
686
|
-
return undefined;
|
|
687
|
-
const required = schema.required.filter((value) => typeof value === 'string');
|
|
688
|
-
if (required.length !== 1)
|
|
689
|
-
return undefined;
|
|
690
|
-
const property = schema.properties[required[0]];
|
|
691
|
-
return isObject(property) && property.type === 'string' ? required[0] : undefined;
|
|
692
|
-
}
|
|
693
677
|
function isObject(value) {
|
|
694
678
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
695
679
|
}
|
|
@@ -32,6 +32,13 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
32
32
|
serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
|
|
33
33
|
hostedWebSearch: boolean;
|
|
34
34
|
responsesToolNamespace?: string | undefined;
|
|
35
|
+
responsesOptionalParameters?: {
|
|
36
|
+
reasoningEffort: boolean;
|
|
37
|
+
reasoningSummary: boolean;
|
|
38
|
+
textVerbosity: boolean;
|
|
39
|
+
promptCacheKey: boolean;
|
|
40
|
+
nativeTools?: boolean | undefined;
|
|
41
|
+
} | undefined;
|
|
35
42
|
enabled: boolean;
|
|
36
43
|
} | {
|
|
37
44
|
credential: {
|
|
@@ -58,5 +65,12 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
58
65
|
serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
|
|
59
66
|
hostedWebSearch: boolean;
|
|
60
67
|
responsesToolNamespace?: string | undefined;
|
|
68
|
+
responsesOptionalParameters?: {
|
|
69
|
+
reasoningEffort: boolean;
|
|
70
|
+
reasoningSummary: boolean;
|
|
71
|
+
textVerbosity: boolean;
|
|
72
|
+
promptCacheKey: boolean;
|
|
73
|
+
nativeTools?: boolean | undefined;
|
|
74
|
+
} | undefined;
|
|
61
75
|
enabled: boolean;
|
|
62
76
|
};
|
|
@@ -90,6 +90,13 @@ declare const rawModelSchema: z.ZodObject<{
|
|
|
90
90
|
}, z.core.$strict>], "transport">>;
|
|
91
91
|
responsesToolNamespace: z.ZodOptional<z.ZodString>;
|
|
92
92
|
responsesPreviousResponseId: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
93
|
+
responsesOptionalParameters: z.ZodOptional<z.ZodObject<{
|
|
94
|
+
reasoningEffort: z.ZodBoolean;
|
|
95
|
+
reasoningSummary: z.ZodBoolean;
|
|
96
|
+
textVerbosity: z.ZodBoolean;
|
|
97
|
+
promptCacheKey: z.ZodBoolean;
|
|
98
|
+
nativeTools: z.ZodOptional<z.ZodBoolean>;
|
|
99
|
+
}, z.core.$strict>>;
|
|
93
100
|
enabled: z.ZodBoolean;
|
|
94
101
|
}, z.core.$strict>;
|
|
95
102
|
export interface MarAgentModelConfiguration extends Omit<z.infer<typeof rawModelSchema>, 'apiKey' | 'responsesPreviousResponseId' | 'responsesTransport'> {
|
|
@@ -58,6 +58,16 @@ const rawModelSchema = z
|
|
|
58
58
|
.regex(/^[a-zA-Z][a-zA-Z0-9_]{0,63}$/u)
|
|
59
59
|
.optional(),
|
|
60
60
|
responsesPreviousResponseId: z.boolean().optional().default(false),
|
|
61
|
+
responsesOptionalParameters: z
|
|
62
|
+
.object({
|
|
63
|
+
reasoningEffort: z.boolean(),
|
|
64
|
+
reasoningSummary: z.boolean(),
|
|
65
|
+
textVerbosity: z.boolean(),
|
|
66
|
+
promptCacheKey: z.boolean(),
|
|
67
|
+
nativeTools: z.boolean().optional()
|
|
68
|
+
})
|
|
69
|
+
.strict()
|
|
70
|
+
.optional(),
|
|
61
71
|
enabled: z.boolean()
|
|
62
72
|
})
|
|
63
73
|
.strict()
|
|
@@ -68,5 +68,5 @@ declare class OpenAiResponsesTurnSession implements ModelTurnSession {
|
|
|
68
68
|
private connectWebSocket;
|
|
69
69
|
}
|
|
70
70
|
export declare function isOpenAiResponsesRecoverableStreamError(error: unknown): error is MarAgentError;
|
|
71
|
-
export declare function openAiInput(messages: ModelRequest['messages'], images: ModelRequest['images'] | undefined, modelId: string, requireEncryptedReasoning: boolean, configurationUpdates?: boolean): Record<string, unknown>[];
|
|
71
|
+
export declare function openAiInput(messages: ModelRequest['messages'], images: ModelRequest['images'] | undefined, modelId: string, requireEncryptedReasoning: boolean, configurationUpdates?: boolean, nativeTools?: boolean, tools?: ModelRequest['tools']): Record<string, unknown>[];
|
|
72
72
|
export {};
|
|
@@ -8,8 +8,9 @@ import { marAgentReasoningEffortSchema, resolveModelDefaultReasoningEffort, uses
|
|
|
8
8
|
import WebSocket from 'ws';
|
|
9
9
|
import { isRetryableUpstreamOverloadCode, number, parseSse, record, text, observeModelStreamEvent, modelStreamEventObservedAt } from './sse.js';
|
|
10
10
|
import { connectSocks5Target, fetchModelResponse, isRetryableModelHttpStatus, isRetryableModelTransportError, modelRetryMaxAttempts, isRetryableModelRequestError, modelRetryDelay, waitForModelRetry } from './http.js';
|
|
11
|
-
import { acquireModelCredential, appendModelCredentialHeaders } from './runtime-credential.js';
|
|
11
|
+
import { acquireModelCredential, appendModelCredentialHeaders, modelCredentialSensitiveValues } from './runtime-credential.js';
|
|
12
12
|
import { resolveModelTextBlocks } from './text-blocks.js';
|
|
13
|
+
import { jsonToolInput } from './tool-input.js';
|
|
13
14
|
import { reportModelAttempt } from './attempt-diagnostics.js';
|
|
14
15
|
const WEBSOCKET_IDLE_TIMEOUT_MS = 300_000;
|
|
15
16
|
const WEBSOCKET_SEND_FRAME_BYTES = 1024 * 1024;
|
|
@@ -253,11 +254,13 @@ export class OpenAiResponsesAdapter {
|
|
|
253
254
|
}
|
|
254
255
|
async *startAttempt(request, signal, body, continuation, credentialReason, turn) {
|
|
255
256
|
let latestCredentialRevision;
|
|
257
|
+
let diagnosticSecrets = [];
|
|
256
258
|
const fetchResponse = async (requestBody) => {
|
|
257
259
|
const serializedBody = JSON.stringify(requestBody);
|
|
258
260
|
return await fetchModelResponse(responsesEndpoint(this.configuration.baseUrl), async () => {
|
|
259
261
|
const credential = await acquireResponsesCredential(this.configuration, credentialReason, signal);
|
|
260
262
|
latestCredentialRevision = credential.revision;
|
|
263
|
+
diagnosticSecrets = modelCredentialSensitiveValues(credential);
|
|
261
264
|
return {
|
|
262
265
|
request: {
|
|
263
266
|
method: 'POST',
|
|
@@ -291,7 +294,7 @@ export class OpenAiResponsesAdapter {
|
|
|
291
294
|
else {
|
|
292
295
|
response = await fetchResponse(body);
|
|
293
296
|
turn.captureTurnState(response.headers.get(X_CODEX_TURN_STATE));
|
|
294
|
-
rawEvents = parseOpenAiResponsesSse(response, signal, continuation);
|
|
297
|
+
rawEvents = parseOpenAiResponsesSse(response, signal, continuation, diagnosticSecrets);
|
|
295
298
|
}
|
|
296
299
|
}
|
|
297
300
|
catch (error) {
|
|
@@ -583,7 +586,9 @@ export class OpenAiResponsesAdapter {
|
|
|
583
586
|
}, modelStreamEventObservedAt(raw));
|
|
584
587
|
completed = true;
|
|
585
588
|
}
|
|
586
|
-
else if (type === 'error' ||
|
|
589
|
+
else if (type === 'error' ||
|
|
590
|
+
type === 'response.failed' ||
|
|
591
|
+
(event.type === undefined && event.error !== undefined)) {
|
|
587
592
|
const topLevel = record(event.error);
|
|
588
593
|
const nested = record(record(event.response).error);
|
|
589
594
|
const code = boundedError(text(event.code) ??
|
|
@@ -591,7 +596,10 @@ export class OpenAiResponsesAdapter {
|
|
|
591
596
|
text(topLevel.type) ??
|
|
592
597
|
text(nested.code) ??
|
|
593
598
|
text(nested.type), 80);
|
|
594
|
-
const message = boundedError(text(event.message) ??
|
|
599
|
+
const message = boundedError(text(event.message) ??
|
|
600
|
+
text(topLevel.message) ??
|
|
601
|
+
text(nested.message) ??
|
|
602
|
+
text(event.error), 1_000);
|
|
595
603
|
const status = upstreamHttpStatus(event.status, topLevel.status, record(event.response).status, nested.status);
|
|
596
604
|
const connectionLimit = this.configuration.responsesTransport?.transport === 'WEBSOCKET' &&
|
|
597
605
|
isWebSocketConnectionLimitCode(code);
|
|
@@ -897,14 +905,15 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
897
905
|
throw new MarAgentError('MAR_AGENT_MODEL_CAPABILITY_UNAVAILABLE', 'This model protocol does not support explicit text-block cache markers.');
|
|
898
906
|
const tools = request.allowTools === false
|
|
899
907
|
? []
|
|
900
|
-
: request.tools.map((tool) => tool.nativeType === 'tool_search'
|
|
908
|
+
: request.tools.map((tool) => tool.nativeType === 'tool_search' &&
|
|
909
|
+
configuration.responsesOptionalParameters?.nativeTools !== false
|
|
901
910
|
? {
|
|
902
911
|
type: 'tool_search',
|
|
903
912
|
execution: 'client',
|
|
904
913
|
description: tool.description,
|
|
905
914
|
parameters: stableToolSchema(strictFunctionSchema(stableToolSchema(tool.inputSchema)))
|
|
906
915
|
}
|
|
907
|
-
: responsesFunctionTool(tool));
|
|
916
|
+
: responsesFunctionTool(tool, configuration.responsesOptionalParameters?.nativeTools !== false));
|
|
908
917
|
if (configuration.responsesToolNamespace && tools.length > 0) {
|
|
909
918
|
const native = tools.filter((tool) => record(tool).type === 'tool_search');
|
|
910
919
|
const nested = tools.filter((tool) => record(tool).type !== 'tool_search');
|
|
@@ -920,7 +929,7 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
920
929
|
if (request.allowTools !== false && configuration.hostedWebSearch)
|
|
921
930
|
tools.push({ type: 'web_search' });
|
|
922
931
|
const toolChoice = request.toolChoice ?? 'auto';
|
|
923
|
-
const input = openAiInput(messages, request.images, configuration.id, true, usesResponsesConfigurationUpdates(configuration));
|
|
932
|
+
const input = openAiInput(messages, request.images, configuration.id, true, usesResponsesConfigurationUpdates(configuration), configuration.responsesOptionalParameters?.nativeTools !== false, request.tools);
|
|
924
933
|
if (request.systemBlocks !== undefined && (request.systemBlocks.length || request.system.length))
|
|
925
934
|
input.unshift({
|
|
926
935
|
role: 'developer',
|
|
@@ -943,25 +952,40 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
943
952
|
: {}),
|
|
944
953
|
instructions: request.systemBlocks === undefined ? request.system : '',
|
|
945
954
|
tools,
|
|
946
|
-
tool_choice: toolChoice,
|
|
955
|
+
...(tools.length > 0 ? { tool_choice: toolChoice, parallel_tool_calls: true } : {}),
|
|
947
956
|
input,
|
|
948
957
|
stream: true,
|
|
949
|
-
parallel_tool_calls: true,
|
|
950
958
|
store: false,
|
|
951
|
-
|
|
959
|
+
...(configuration.responsesOptionalParameters?.textVerbosity === false
|
|
960
|
+
? {}
|
|
961
|
+
: { text: { verbosity: 'low' } }),
|
|
952
962
|
include: [
|
|
953
963
|
'reasoning.encrypted_content',
|
|
954
964
|
...(configuration.hostedWebSearch && request.allowTools !== false && toolChoice !== 'none'
|
|
955
965
|
? ['web_search_call.action.sources']
|
|
956
966
|
: [])
|
|
957
967
|
],
|
|
958
|
-
...(request.promptCacheKey
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
968
|
+
...(request.promptCacheKey &&
|
|
969
|
+
configuration.responsesOptionalParameters?.promptCacheKey !== false
|
|
970
|
+
? { prompt_cache_key: request.promptCacheKey }
|
|
971
|
+
: {}),
|
|
972
|
+
...(configuration.responsesOptionalParameters?.reasoningEffort === false &&
|
|
973
|
+
configuration.responsesOptionalParameters?.reasoningSummary === false
|
|
974
|
+
? {}
|
|
975
|
+
: {
|
|
976
|
+
reasoning: {
|
|
977
|
+
...(configuration.responsesOptionalParameters?.reasoningEffort === false
|
|
978
|
+
? {}
|
|
979
|
+
: {
|
|
980
|
+
effort: request.requestReasoningEffort?.trim() ||
|
|
981
|
+
request.reasoningEffort?.trim() ||
|
|
982
|
+
resolveModelDefaultReasoningEffort(configuration)
|
|
983
|
+
}),
|
|
984
|
+
...(configuration.responsesOptionalParameters?.reasoningSummary === false
|
|
985
|
+
? {}
|
|
986
|
+
: { summary: 'auto' })
|
|
987
|
+
}
|
|
988
|
+
})
|
|
965
989
|
};
|
|
966
990
|
}
|
|
967
991
|
function incrementalResponsesInput(state, current) {
|
|
@@ -1031,9 +1055,9 @@ function turnStateFromEvent(event) {
|
|
|
1031
1055
|
}
|
|
1032
1056
|
return undefined;
|
|
1033
1057
|
}
|
|
1034
|
-
async function* parseOpenAiResponsesSse(response, signal, continuation) {
|
|
1058
|
+
async function* parseOpenAiResponsesSse(response, signal, continuation, sensitiveValues) {
|
|
1035
1059
|
try {
|
|
1036
|
-
yield* parseSse(response, signal);
|
|
1060
|
+
yield* parseSse(response, signal, undefined, undefined, sensitiveValues);
|
|
1037
1061
|
}
|
|
1038
1062
|
catch (cause) {
|
|
1039
1063
|
if (response.ok && !signal.aborted && isRetryableOpenAiStreamReadError(cause))
|
|
@@ -1771,11 +1795,13 @@ function responseCitations(response) {
|
|
|
1771
1795
|
function responseEventId(event) {
|
|
1772
1796
|
return text(record(event.response).id);
|
|
1773
1797
|
}
|
|
1774
|
-
export function openAiInput(messages, images, modelId, requireEncryptedReasoning, configurationUpdates = true) {
|
|
1798
|
+
export function openAiInput(messages, images, modelId, requireEncryptedReasoning, configurationUpdates = true, nativeTools = true, tools = []) {
|
|
1775
1799
|
const compatibleMessages = messages.filter((message) => message.role !== 'provider' ||
|
|
1776
1800
|
(message.provider === 'OPENAI_RESPONSES' &&
|
|
1777
1801
|
(message.providerModelId === undefined || message.providerModelId === modelId) &&
|
|
1778
1802
|
(configurationUpdates || message.item?.type !== 'configuration_update') &&
|
|
1803
|
+
(nativeTools ||
|
|
1804
|
+
!['custom_tool_call', 'tool_search_call', 'tool_search_output'].includes(String(message.item?.type))) &&
|
|
1779
1805
|
(!requireEncryptedReasoning ||
|
|
1780
1806
|
message.item?.type !== 'reasoning' ||
|
|
1781
1807
|
typeof message.item.encrypted_content === 'string')));
|
|
@@ -1810,7 +1836,10 @@ export function openAiInput(messages, images, modelId, requireEncryptedReasoning
|
|
|
1810
1836
|
}
|
|
1811
1837
|
}
|
|
1812
1838
|
for (const message of compatibleMessages)
|
|
1813
|
-
if (
|
|
1839
|
+
if (nativeTools &&
|
|
1840
|
+
message.role === 'tool_call' &&
|
|
1841
|
+
message.inputMode === 'freeform' &&
|
|
1842
|
+
message.callId)
|
|
1814
1843
|
customCallIds.add(message.callId);
|
|
1815
1844
|
const orderedMessages = [];
|
|
1816
1845
|
for (const message of compatibleMessages) {
|
|
@@ -1828,9 +1857,9 @@ export function openAiInput(messages, images, modelId, requireEncryptedReasoning
|
|
|
1828
1857
|
return orderedMessages
|
|
1829
1858
|
.filter((message) => !(message.role === 'tool_call' && message.callId && providerCallIds.has(message.callId)) &&
|
|
1830
1859
|
!(message.role === 'assistant' && providerMessageTexts.has(message.content)))
|
|
1831
|
-
.map((message) => openAiInputItem(message, message === lastUser ? images : undefined, customCallIds, functionCallIds));
|
|
1860
|
+
.map((message) => openAiInputItem(message, message === lastUser ? images : undefined, customCallIds, functionCallIds, nativeTools, tools));
|
|
1832
1861
|
}
|
|
1833
|
-
function openAiInputItem(message, images, customCallIds = new Set(), functionCallIds = new Set()) {
|
|
1862
|
+
function openAiInputItem(message, images, customCallIds = new Set(), functionCallIds = new Set(), nativeTools = true, tools = []) {
|
|
1834
1863
|
const userImages = message.role === 'user' ? uniqueModelImages(message.images, images) : [];
|
|
1835
1864
|
if (message.role === 'provider') {
|
|
1836
1865
|
if (message.provider !== 'OPENAI_RESPONSES' || !message.item)
|
|
@@ -1845,14 +1874,14 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1845
1874
|
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Provider context item type is unsupported.');
|
|
1846
1875
|
return item;
|
|
1847
1876
|
}
|
|
1848
|
-
if (message.role === 'tool_call' && message.inputMode === 'freeform')
|
|
1877
|
+
if (nativeTools && message.role === 'tool_call' && message.inputMode === 'freeform')
|
|
1849
1878
|
return {
|
|
1850
1879
|
type: 'custom_tool_call',
|
|
1851
1880
|
call_id: message.callId,
|
|
1852
1881
|
name: message.name,
|
|
1853
1882
|
input: String(message.arguments ?? '')
|
|
1854
1883
|
};
|
|
1855
|
-
if (message.role === 'tool_call' && message.name === 'tool_search')
|
|
1884
|
+
if (nativeTools && message.role === 'tool_call' && message.name === 'tool_search')
|
|
1856
1885
|
return {
|
|
1857
1886
|
type: 'tool_search_call',
|
|
1858
1887
|
call_id: message.callId,
|
|
@@ -1865,9 +1894,12 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1865
1894
|
type: 'function_call',
|
|
1866
1895
|
call_id: message.callId,
|
|
1867
1896
|
name: message.name,
|
|
1868
|
-
arguments: JSON.stringify(message.
|
|
1897
|
+
arguments: JSON.stringify(message.inputMode === 'freeform'
|
|
1898
|
+
? jsonToolInput(message, tools.find((tool) => tool.name === message.name))
|
|
1899
|
+
: (message.arguments ?? {}))
|
|
1869
1900
|
};
|
|
1870
1901
|
if (message.role === 'tool' &&
|
|
1902
|
+
nativeTools &&
|
|
1871
1903
|
message.toolSearchTools &&
|
|
1872
1904
|
!functionCallIds.has(message.callId ?? ''))
|
|
1873
1905
|
return {
|
|
@@ -1875,7 +1907,7 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1875
1907
|
call_id: message.callId,
|
|
1876
1908
|
status: 'completed',
|
|
1877
1909
|
execution: 'client',
|
|
1878
|
-
tools: message.toolSearchTools.map(responsesFunctionTool)
|
|
1910
|
+
tools: message.toolSearchTools.map((tool) => responsesFunctionTool(tool))
|
|
1879
1911
|
};
|
|
1880
1912
|
if (message.role === 'tool')
|
|
1881
1913
|
return {
|
|
@@ -1934,9 +1966,9 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1934
1966
|
: message.content
|
|
1935
1967
|
};
|
|
1936
1968
|
}
|
|
1937
|
-
function responsesFunctionTool(tool) {
|
|
1969
|
+
function responsesFunctionTool(tool, nativeTools = true) {
|
|
1938
1970
|
const strict = !hasOpenFunctionObject(tool.inputSchema);
|
|
1939
|
-
return tool.inputMode === 'freeform'
|
|
1971
|
+
return tool.inputMode === 'freeform' && nativeTools
|
|
1940
1972
|
? { type: 'custom', name: tool.name, description: tool.description }
|
|
1941
1973
|
: {
|
|
1942
1974
|
type: 'function',
|
|
@@ -4,3 +4,5 @@ export declare function acquireModelCredential(configuration: Pick<MarAgentModel
|
|
|
4
4
|
readonly credentialProvider?: ModelCredentialProvider;
|
|
5
5
|
}, reason: ModelCredentialAcquireReason, missingCredentialMessage: string, signal?: AbortSignal): Promise<ModelCredential>;
|
|
6
6
|
export declare function appendModelCredentialHeaders(headers: Headers, credential: ModelCredential, reservedHeaders: ReadonlySet<string>): Headers;
|
|
7
|
+
/** Values known to be credentials, used only when producing public HTTP error diagnostics. */
|
|
8
|
+
export declare function modelCredentialSensitiveValues(credential: ModelCredential): readonly string[];
|
|
@@ -55,3 +55,18 @@ export function appendModelCredentialHeaders(headers, credential, reservedHeader
|
|
|
55
55
|
}
|
|
56
56
|
return headers;
|
|
57
57
|
}
|
|
58
|
+
/** Values known to be credentials, used only when producing public HTTP error diagnostics. */
|
|
59
|
+
export function modelCredentialSensitiveValues(credential) {
|
|
60
|
+
const values = [
|
|
61
|
+
credential.bearer.reveal(),
|
|
62
|
+
...Object.values(credential.headers)
|
|
63
|
+
.filter((value) => value instanceof SecretValue)
|
|
64
|
+
.map((value) => value.reveal())
|
|
65
|
+
];
|
|
66
|
+
if (credential.socks5Url !== undefined) {
|
|
67
|
+
const proxy = credential.socks5Url.reveal();
|
|
68
|
+
const url = new URL(proxy);
|
|
69
|
+
values.push(proxy, decodeURIComponent(url.username), decodeURIComponent(url.password));
|
|
70
|
+
}
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function observeModelStreamEvent<const T>(value: T, observedAt: number | undefined): T;
|
|
2
2
|
export declare function modelStreamEventObservedAt(value: unknown): number | undefined;
|
|
3
|
-
export declare function parseSse(response: Response, signal: AbortSignal, maxBytes?: number, idleTimeoutMs?: number): AsyncIterable<unknown>;
|
|
3
|
+
export declare function parseSse(response: Response, signal: AbortSignal, maxBytes?: number, idleTimeoutMs?: number, sensitiveValues?: readonly string[]): AsyncIterable<unknown>;
|
|
4
4
|
export declare function isRetryableUpstreamOverloadCode(code: string | undefined): boolean;
|
|
5
5
|
export declare function record(value: unknown): Record<string, unknown>;
|
|
6
6
|
export declare function text(value: unknown): string | undefined;
|
|
@@ -10,9 +10,14 @@ export function observeModelStreamEvent(value, observedAt) {
|
|
|
10
10
|
export function modelStreamEventObservedAt(value) {
|
|
11
11
|
return typeof value === 'object' && value !== null ? streamEventObservedAt.get(value) : undefined;
|
|
12
12
|
}
|
|
13
|
-
export async function* parseSse(response, signal, maxBytes = 16 * 1024 * 1024, idleTimeoutMs = DEFAULT_MODEL_STREAM_IDLE_TIMEOUT_MS) {
|
|
13
|
+
export async function* parseSse(response, signal, maxBytes = 16 * 1024 * 1024, idleTimeoutMs = DEFAULT_MODEL_STREAM_IDLE_TIMEOUT_MS, sensitiveValues = []) {
|
|
14
14
|
if (!response.ok) {
|
|
15
|
-
const
|
|
15
|
+
const redact = responseRedactor(sensitiveValues);
|
|
16
|
+
const body = redact(await readResponseText(response, signal, maxBytes, idleTimeoutMs));
|
|
17
|
+
const header = (name, limit) => {
|
|
18
|
+
const value = response.headers.get(name);
|
|
19
|
+
return value === null ? null : redact(value).slice(0, limit);
|
|
20
|
+
};
|
|
16
21
|
const upstream = upstreamError(body);
|
|
17
22
|
const code = upstream?.code ??
|
|
18
23
|
(response.status === 401 || response.status === 403
|
|
@@ -25,8 +30,11 @@ export async function* parseSse(response, signal, maxBytes = 16 * 1024 * 1024, i
|
|
|
25
30
|
throw new MarAgentError(code, upstream?.message ?? `Model endpoint returned HTTP ${response.status}.`, {
|
|
26
31
|
details: {
|
|
27
32
|
status: response.status,
|
|
28
|
-
body: body.slice(0,
|
|
29
|
-
|
|
33
|
+
body: body.slice(0, 4096),
|
|
34
|
+
bodyTruncated: body.length > 4096,
|
|
35
|
+
contentType: header('content-type', 256),
|
|
36
|
+
requestId: header('x-request-id', 256) ?? header('request-id', 256),
|
|
37
|
+
retryAfter: header('retry-after', 128)
|
|
30
38
|
},
|
|
31
39
|
retryable: isRetryableModelHttpStatus(response.status)
|
|
32
40
|
});
|
|
@@ -208,6 +216,12 @@ async function readStreamChunk(reader, signal, idleTimeoutMs) {
|
|
|
208
216
|
});
|
|
209
217
|
});
|
|
210
218
|
}
|
|
219
|
+
function responseRedactor(sensitiveValues) {
|
|
220
|
+
const secrets = [
|
|
221
|
+
...new Set(sensitiveValues.flatMap((value) => value ? [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value)] : []))
|
|
222
|
+
].sort((left, right) => right.length - left.length);
|
|
223
|
+
return (value) => secrets.reduce((text, secret) => text.replaceAll(secret, '[REDACTED]'), value);
|
|
224
|
+
}
|
|
211
225
|
function upstreamError(body) {
|
|
212
226
|
let parsed;
|
|
213
227
|
try {
|
|
@@ -217,6 +231,10 @@ function upstreamError(body) {
|
|
|
217
231
|
return undefined;
|
|
218
232
|
}
|
|
219
233
|
const root = record(parsed);
|
|
234
|
+
if (typeof root.error === 'string') {
|
|
235
|
+
const message = bounded(root.error, 1_000);
|
|
236
|
+
return message === undefined ? undefined : { message };
|
|
237
|
+
}
|
|
220
238
|
const error = record(root.error);
|
|
221
239
|
// K3-compatible gateways can put the error discriminator in `type` and omit `code`.
|
|
222
240
|
const code = bounded(text(error.code) ?? text(error.type), 80);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ModelRequest } from './contracts.js';
|
|
2
|
+
/** Preserve a freeform call when replaying it through a JSON-only tool protocol. */
|
|
3
|
+
export declare function jsonToolInput(message: ModelRequest['messages'][number], tool: ModelRequest['tools'][number] | undefined): Record<string, unknown>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Preserve a freeform call when replaying it through a JSON-only tool protocol. */
|
|
2
|
+
export function jsonToolInput(message, tool) {
|
|
3
|
+
if (isObject(message.arguments))
|
|
4
|
+
return message.arguments;
|
|
5
|
+
if (message.inputMode !== 'freeform')
|
|
6
|
+
return {};
|
|
7
|
+
const schema = tool?.inputSchema;
|
|
8
|
+
const required = schema?.type === 'object' && Array.isArray(schema.required)
|
|
9
|
+
? schema.required.filter((value) => typeof value === 'string')
|
|
10
|
+
: [];
|
|
11
|
+
const name = required.length === 1 && typeof required[0] === 'string' ? required[0] : undefined;
|
|
12
|
+
const property = name && isObject(schema?.properties) ? schema.properties[name] : undefined;
|
|
13
|
+
const key = name && isObject(property) && property.type === 'string' ? name : 'input';
|
|
14
|
+
return { [key]: String(message.arguments ?? '') };
|
|
15
|
+
}
|
|
16
|
+
function isObject(value) {
|
|
17
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
18
|
+
}
|
|
@@ -34,6 +34,6 @@ export class ModelGenerationTiming {
|
|
|
34
34
|
this.completed = true;
|
|
35
35
|
}
|
|
36
36
|
get durationMs() {
|
|
37
|
-
return this.completed && this.valid && this.duration >=
|
|
37
|
+
return this.completed && this.valid && this.duration >= 1_000 ? this.duration : undefined;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -26,7 +26,7 @@ export const codeModeToolDefinition = {
|
|
|
26
26
|
- Observe only evidence needed for the next decision or verification: use observe.result for original results, observe.text for derived values, and observe.image for image values. Preserve source and failure details needed for reasoning; keep other intermediate data in the cell.
|
|
27
27
|
- Single-tool cells are valid. Keep loops and retries bounded, and do not blindly replay operations with side effects.
|
|
28
28
|
- Evaluates source in a fresh restricted ECMAScript runtime with top-level await and Promise.all. It is not Node.js or a browser. JavaScript globals do not survive between cells; bounded JSON state is available through state.
|
|
29
|
-
- Accepts
|
|
29
|
+
- Accepts JavaScript source text. When exposed as a freeform tool, send the source directly; when exposed with a JSON input schema, put the source in its code field. Do not add another JSON wrapper, quoted string, or markdown code fence inside the source.
|
|
30
30
|
- Use only standard ECMAScript built-ins and the explicitly documented tools, observe, state, catalog and cell namespaces. Do not use Node.js, browser or Web APIs. Module imports, filesystem and network APIs are unavailable. Obtain external capabilities only through available tools. Use tools.exec to start managed processes when permitted; use tools.exec_wait afterward to wait, write stdin or cancel.
|
|
31
31
|
|
|
32
32
|
Tool calls:
|