@myagentroam/agent 0.10.8 → 0.10.9
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 +54 -27
- 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/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) {
|
|
@@ -897,14 +900,15 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
897
900
|
throw new MarAgentError('MAR_AGENT_MODEL_CAPABILITY_UNAVAILABLE', 'This model protocol does not support explicit text-block cache markers.');
|
|
898
901
|
const tools = request.allowTools === false
|
|
899
902
|
? []
|
|
900
|
-
: request.tools.map((tool) => tool.nativeType === 'tool_search'
|
|
903
|
+
: request.tools.map((tool) => tool.nativeType === 'tool_search' &&
|
|
904
|
+
configuration.responsesOptionalParameters?.nativeTools !== false
|
|
901
905
|
? {
|
|
902
906
|
type: 'tool_search',
|
|
903
907
|
execution: 'client',
|
|
904
908
|
description: tool.description,
|
|
905
909
|
parameters: stableToolSchema(strictFunctionSchema(stableToolSchema(tool.inputSchema)))
|
|
906
910
|
}
|
|
907
|
-
: responsesFunctionTool(tool));
|
|
911
|
+
: responsesFunctionTool(tool, configuration.responsesOptionalParameters?.nativeTools !== false));
|
|
908
912
|
if (configuration.responsesToolNamespace && tools.length > 0) {
|
|
909
913
|
const native = tools.filter((tool) => record(tool).type === 'tool_search');
|
|
910
914
|
const nested = tools.filter((tool) => record(tool).type !== 'tool_search');
|
|
@@ -920,7 +924,7 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
920
924
|
if (request.allowTools !== false && configuration.hostedWebSearch)
|
|
921
925
|
tools.push({ type: 'web_search' });
|
|
922
926
|
const toolChoice = request.toolChoice ?? 'auto';
|
|
923
|
-
const input = openAiInput(messages, request.images, configuration.id, true, usesResponsesConfigurationUpdates(configuration));
|
|
927
|
+
const input = openAiInput(messages, request.images, configuration.id, true, usesResponsesConfigurationUpdates(configuration), configuration.responsesOptionalParameters?.nativeTools !== false, request.tools);
|
|
924
928
|
if (request.systemBlocks !== undefined && (request.systemBlocks.length || request.system.length))
|
|
925
929
|
input.unshift({
|
|
926
930
|
role: 'developer',
|
|
@@ -943,25 +947,40 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
943
947
|
: {}),
|
|
944
948
|
instructions: request.systemBlocks === undefined ? request.system : '',
|
|
945
949
|
tools,
|
|
946
|
-
tool_choice: toolChoice,
|
|
950
|
+
...(tools.length > 0 ? { tool_choice: toolChoice, parallel_tool_calls: true } : {}),
|
|
947
951
|
input,
|
|
948
952
|
stream: true,
|
|
949
|
-
parallel_tool_calls: true,
|
|
950
953
|
store: false,
|
|
951
|
-
|
|
954
|
+
...(configuration.responsesOptionalParameters?.textVerbosity === false
|
|
955
|
+
? {}
|
|
956
|
+
: { text: { verbosity: 'low' } }),
|
|
952
957
|
include: [
|
|
953
958
|
'reasoning.encrypted_content',
|
|
954
959
|
...(configuration.hostedWebSearch && request.allowTools !== false && toolChoice !== 'none'
|
|
955
960
|
? ['web_search_call.action.sources']
|
|
956
961
|
: [])
|
|
957
962
|
],
|
|
958
|
-
...(request.promptCacheKey
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
963
|
+
...(request.promptCacheKey &&
|
|
964
|
+
configuration.responsesOptionalParameters?.promptCacheKey !== false
|
|
965
|
+
? { prompt_cache_key: request.promptCacheKey }
|
|
966
|
+
: {}),
|
|
967
|
+
...(configuration.responsesOptionalParameters?.reasoningEffort === false &&
|
|
968
|
+
configuration.responsesOptionalParameters?.reasoningSummary === false
|
|
969
|
+
? {}
|
|
970
|
+
: {
|
|
971
|
+
reasoning: {
|
|
972
|
+
...(configuration.responsesOptionalParameters?.reasoningEffort === false
|
|
973
|
+
? {}
|
|
974
|
+
: {
|
|
975
|
+
effort: request.requestReasoningEffort?.trim() ||
|
|
976
|
+
request.reasoningEffort?.trim() ||
|
|
977
|
+
resolveModelDefaultReasoningEffort(configuration)
|
|
978
|
+
}),
|
|
979
|
+
...(configuration.responsesOptionalParameters?.reasoningSummary === false
|
|
980
|
+
? {}
|
|
981
|
+
: { summary: 'auto' })
|
|
982
|
+
}
|
|
983
|
+
})
|
|
965
984
|
};
|
|
966
985
|
}
|
|
967
986
|
function incrementalResponsesInput(state, current) {
|
|
@@ -1031,9 +1050,9 @@ function turnStateFromEvent(event) {
|
|
|
1031
1050
|
}
|
|
1032
1051
|
return undefined;
|
|
1033
1052
|
}
|
|
1034
|
-
async function* parseOpenAiResponsesSse(response, signal, continuation) {
|
|
1053
|
+
async function* parseOpenAiResponsesSse(response, signal, continuation, sensitiveValues) {
|
|
1035
1054
|
try {
|
|
1036
|
-
yield* parseSse(response, signal);
|
|
1055
|
+
yield* parseSse(response, signal, undefined, undefined, sensitiveValues);
|
|
1037
1056
|
}
|
|
1038
1057
|
catch (cause) {
|
|
1039
1058
|
if (response.ok && !signal.aborted && isRetryableOpenAiStreamReadError(cause))
|
|
@@ -1771,11 +1790,13 @@ function responseCitations(response) {
|
|
|
1771
1790
|
function responseEventId(event) {
|
|
1772
1791
|
return text(record(event.response).id);
|
|
1773
1792
|
}
|
|
1774
|
-
export function openAiInput(messages, images, modelId, requireEncryptedReasoning, configurationUpdates = true) {
|
|
1793
|
+
export function openAiInput(messages, images, modelId, requireEncryptedReasoning, configurationUpdates = true, nativeTools = true, tools = []) {
|
|
1775
1794
|
const compatibleMessages = messages.filter((message) => message.role !== 'provider' ||
|
|
1776
1795
|
(message.provider === 'OPENAI_RESPONSES' &&
|
|
1777
1796
|
(message.providerModelId === undefined || message.providerModelId === modelId) &&
|
|
1778
1797
|
(configurationUpdates || message.item?.type !== 'configuration_update') &&
|
|
1798
|
+
(nativeTools ||
|
|
1799
|
+
!['custom_tool_call', 'tool_search_call', 'tool_search_output'].includes(String(message.item?.type))) &&
|
|
1779
1800
|
(!requireEncryptedReasoning ||
|
|
1780
1801
|
message.item?.type !== 'reasoning' ||
|
|
1781
1802
|
typeof message.item.encrypted_content === 'string')));
|
|
@@ -1810,7 +1831,10 @@ export function openAiInput(messages, images, modelId, requireEncryptedReasoning
|
|
|
1810
1831
|
}
|
|
1811
1832
|
}
|
|
1812
1833
|
for (const message of compatibleMessages)
|
|
1813
|
-
if (
|
|
1834
|
+
if (nativeTools &&
|
|
1835
|
+
message.role === 'tool_call' &&
|
|
1836
|
+
message.inputMode === 'freeform' &&
|
|
1837
|
+
message.callId)
|
|
1814
1838
|
customCallIds.add(message.callId);
|
|
1815
1839
|
const orderedMessages = [];
|
|
1816
1840
|
for (const message of compatibleMessages) {
|
|
@@ -1828,9 +1852,9 @@ export function openAiInput(messages, images, modelId, requireEncryptedReasoning
|
|
|
1828
1852
|
return orderedMessages
|
|
1829
1853
|
.filter((message) => !(message.role === 'tool_call' && message.callId && providerCallIds.has(message.callId)) &&
|
|
1830
1854
|
!(message.role === 'assistant' && providerMessageTexts.has(message.content)))
|
|
1831
|
-
.map((message) => openAiInputItem(message, message === lastUser ? images : undefined, customCallIds, functionCallIds));
|
|
1855
|
+
.map((message) => openAiInputItem(message, message === lastUser ? images : undefined, customCallIds, functionCallIds, nativeTools, tools));
|
|
1832
1856
|
}
|
|
1833
|
-
function openAiInputItem(message, images, customCallIds = new Set(), functionCallIds = new Set()) {
|
|
1857
|
+
function openAiInputItem(message, images, customCallIds = new Set(), functionCallIds = new Set(), nativeTools = true, tools = []) {
|
|
1834
1858
|
const userImages = message.role === 'user' ? uniqueModelImages(message.images, images) : [];
|
|
1835
1859
|
if (message.role === 'provider') {
|
|
1836
1860
|
if (message.provider !== 'OPENAI_RESPONSES' || !message.item)
|
|
@@ -1845,14 +1869,14 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1845
1869
|
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Provider context item type is unsupported.');
|
|
1846
1870
|
return item;
|
|
1847
1871
|
}
|
|
1848
|
-
if (message.role === 'tool_call' && message.inputMode === 'freeform')
|
|
1872
|
+
if (nativeTools && message.role === 'tool_call' && message.inputMode === 'freeform')
|
|
1849
1873
|
return {
|
|
1850
1874
|
type: 'custom_tool_call',
|
|
1851
1875
|
call_id: message.callId,
|
|
1852
1876
|
name: message.name,
|
|
1853
1877
|
input: String(message.arguments ?? '')
|
|
1854
1878
|
};
|
|
1855
|
-
if (message.role === 'tool_call' && message.name === 'tool_search')
|
|
1879
|
+
if (nativeTools && message.role === 'tool_call' && message.name === 'tool_search')
|
|
1856
1880
|
return {
|
|
1857
1881
|
type: 'tool_search_call',
|
|
1858
1882
|
call_id: message.callId,
|
|
@@ -1865,9 +1889,12 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1865
1889
|
type: 'function_call',
|
|
1866
1890
|
call_id: message.callId,
|
|
1867
1891
|
name: message.name,
|
|
1868
|
-
arguments: JSON.stringify(message.
|
|
1892
|
+
arguments: JSON.stringify(message.inputMode === 'freeform'
|
|
1893
|
+
? jsonToolInput(message, tools.find((tool) => tool.name === message.name))
|
|
1894
|
+
: (message.arguments ?? {}))
|
|
1869
1895
|
};
|
|
1870
1896
|
if (message.role === 'tool' &&
|
|
1897
|
+
nativeTools &&
|
|
1871
1898
|
message.toolSearchTools &&
|
|
1872
1899
|
!functionCallIds.has(message.callId ?? ''))
|
|
1873
1900
|
return {
|
|
@@ -1875,7 +1902,7 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1875
1902
|
call_id: message.callId,
|
|
1876
1903
|
status: 'completed',
|
|
1877
1904
|
execution: 'client',
|
|
1878
|
-
tools: message.toolSearchTools.map(responsesFunctionTool)
|
|
1905
|
+
tools: message.toolSearchTools.map((tool) => responsesFunctionTool(tool))
|
|
1879
1906
|
};
|
|
1880
1907
|
if (message.role === 'tool')
|
|
1881
1908
|
return {
|
|
@@ -1934,9 +1961,9 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1934
1961
|
: message.content
|
|
1935
1962
|
};
|
|
1936
1963
|
}
|
|
1937
|
-
function responsesFunctionTool(tool) {
|
|
1964
|
+
function responsesFunctionTool(tool, nativeTools = true) {
|
|
1938
1965
|
const strict = !hasOpenFunctionObject(tool.inputSchema);
|
|
1939
|
-
return tool.inputMode === 'freeform'
|
|
1966
|
+
return tool.inputMode === 'freeform' && nativeTools
|
|
1940
1967
|
? { type: 'custom', name: tool.name, description: tool.description }
|
|
1941
1968
|
: {
|
|
1942
1969
|
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
|
+
}
|
|
@@ -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:
|