@myagentroam/agent 0.9.158 → 0.9.160
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/extensions/agents.d.ts +69 -0
- package/dist/agent-core/extensions/agents.js +160 -0
- package/dist/agent-core/extensions/contracts.d.ts +260 -0
- package/dist/agent-core/extensions/contracts.js +1 -0
- package/dist/agent-core/extensions/data.d.ts +84 -0
- package/dist/agent-core/extensions/data.js +83 -0
- package/dist/agent-core/extensions/environment.d.ts +27 -0
- package/dist/agent-core/extensions/environment.js +52 -0
- package/dist/agent-core/extensions/files.d.ts +64 -0
- package/dist/agent-core/extensions/files.js +26 -0
- package/dist/agent-core/extensions/hooks.d.ts +32 -0
- package/dist/agent-core/extensions/hooks.js +135 -0
- package/dist/agent-core/extensions/manager.d.ts +39 -0
- package/dist/agent-core/extensions/manager.js +458 -0
- package/dist/agent-core/extensions/mcp.d.ts +99 -0
- package/dist/agent-core/extensions/mcp.js +433 -0
- package/dist/agent-core/extensions/model-request.d.ts +60 -0
- package/dist/agent-core/extensions/model-request.js +167 -0
- package/dist/agent-core/extensions/model-stream.d.ts +9 -0
- package/dist/agent-core/extensions/model-stream.js +101 -0
- package/dist/agent-core/extensions/models.d.ts +43 -0
- package/dist/agent-core/extensions/models.js +1 -0
- package/dist/agent-core/extensions/network.d.ts +32 -0
- package/dist/agent-core/extensions/network.js +97 -0
- package/dist/agent-core/extensions/operation.d.ts +29 -0
- package/dist/agent-core/extensions/operation.js +98 -0
- package/dist/agent-core/extensions/processes.d.ts +52 -0
- package/dist/agent-core/extensions/processes.js +283 -0
- package/dist/agent-core/extensions/prompt-composition.d.ts +24 -0
- package/dist/agent-core/extensions/prompt-composition.js +106 -0
- package/dist/agent-core/extensions/prompt-input.d.ts +23 -0
- package/dist/agent-core/extensions/prompt-input.js +46 -0
- package/dist/agent-core/extensions/resources.d.ts +27 -0
- package/dist/agent-core/extensions/resources.js +221 -0
- package/dist/agent-core/extensions/services.d.ts +31 -0
- package/dist/agent-core/extensions/services.js +61 -0
- package/dist/agent-core/extensions/session-input.d.ts +151 -0
- package/dist/agent-core/extensions/session-input.js +351 -0
- package/dist/agent-core/extensions/session-messages.d.ts +41 -0
- package/dist/agent-core/extensions/session-messages.js +76 -0
- package/dist/agent-core/extensions/session.d.ts +68 -0
- package/dist/agent-core/extensions/session.js +593 -0
- package/dist/agent-core/extensions/settings.d.ts +59 -0
- package/dist/agent-core/extensions/settings.js +115 -0
- package/dist/agent-core/extensions/store.d.ts +10 -0
- package/dist/agent-core/extensions/store.js +131 -0
- package/dist/agent-core/extensions/tools.d.ts +61 -0
- package/dist/agent-core/extensions/tools.js +266 -0
- package/dist/agent-core/host/contracts.d.ts +25 -0
- package/dist/agent-core/host/local-agent-host.d.ts +10 -1
- package/dist/agent-core/host/local-agent-host.js +132 -20
- package/dist/agent-core/host/local-file-access.d.ts +30 -0
- package/dist/agent-core/host/local-file-access.js +107 -0
- package/dist/agent-core/host/local-network-access.d.ts +6 -0
- package/dist/agent-core/host/local-network-access.js +97 -0
- package/dist/agent-core/host/local-process-executor.d.ts +5 -1
- package/dist/agent-core/host/local-session-environment.d.ts +18 -0
- package/dist/agent-core/host/local-session-environment.js +102 -0
- package/dist/agent-core/model/anthropic-messages.js +73 -23
- package/dist/agent-core/model/contracts.d.ts +21 -0
- package/dist/agent-core/model/openai-responses.d.ts +3 -1
- package/dist/agent-core/model/openai-responses.js +248 -97
- package/dist/agent-core/model/text-blocks.d.ts +7 -0
- package/dist/agent-core/model/text-blocks.js +40 -0
- package/dist/agent-core/prompts/index.d.ts +6 -2
- package/dist/agent-core/prompts/index.js +38 -24
- package/dist/agent-core/runtime/context/gc-tokens.js +6 -1
- package/dist/agent-core/runtime/context/normalize.js +21 -1
- package/dist/agent-core/runtime/context/projection.js +35 -1
- package/dist/agent-core/runtime/context/request-budget.js +5 -2
- package/dist/agent-core/runtime/context/restore.d.ts +5 -0
- package/dist/agent-core/runtime/context/restore.js +47 -4
- package/dist/agent-core/runtime/context/usage.js +2 -3
- package/dist/agent-core/runtime/contracts.d.ts +2 -0
- package/dist/agent-core/runtime/execution.js +5 -2
- package/dist/agent-core/sdk/agent.js +177 -40
- package/dist/agent-core/sdk/extension-agents.d.ts +9 -0
- package/dist/agent-core/sdk/extension-agents.js +51 -0
- package/dist/agent-core/sdk/extension-models.d.ts +13 -0
- package/dist/agent-core/sdk/extension-models.js +128 -0
- package/dist/agent-core/sdk/extension-session.d.ts +30 -0
- package/dist/agent-core/sdk/extension-session.js +103 -0
- package/dist/agent-core/sdk/extension-tools.d.ts +16 -0
- package/dist/agent-core/sdk/extension-tools.js +126 -0
- package/dist/agent-core/sdk/session.d.ts +26 -2
- package/dist/agent-core/sdk/session.js +1215 -506
- package/dist/agent-core/sdk/types.d.ts +3 -0
- package/dist/agent-core/session/context-gc-checkpoint.js +1 -1
- package/dist/agent-core/session/jsonl-store.d.ts +28 -8
- package/dist/agent-core/session/jsonl-store.js +124 -84
- package/dist/agent-core/session/types.d.ts +4 -1
- package/dist/agent-core/storage/file-lock.d.ts +4 -0
- package/dist/agent-core/storage/file-lock.js +83 -0
- package/dist/agent-core/subagent/contracts.d.ts +11 -1
- package/dist/agent-core/subagent/scheduler.d.ts +8 -0
- package/dist/agent-core/subagent/session-controller.d.ts +22 -1
- package/dist/agent-core/subagent/session-controller.js +355 -98
- package/dist/agent-core/tools/agent/agent-start.d.ts +1 -1
- package/dist/agent-core/tools/code-mode/cells.js +5 -15
- package/dist/agent-core/tools/code-mode/dispatch.d.ts +1 -0
- package/dist/agent-core/tools/code-mode/dispatch.js +13 -1
- package/dist/agent-core/tools/code-mode/index.js +1 -2
- package/dist/agent-core/tools/code-mode/observations.d.ts +5 -0
- package/dist/agent-core/tools/code-mode/observations.js +16 -5
- package/dist/agent-core/tools/code-mode/quickjs-engine.js +10 -5
- package/dist/agent-core/tools/execution.d.ts +11 -2
- package/dist/agent-core/tools/execution.js +58 -21
- package/dist/agent-core/tools/input.d.ts +2 -0
- package/dist/agent-core/tools/input.js +36 -0
- package/dist/agent-core/tools/local/apply-patch.js +21 -17
- package/dist/agent-core/tools/local/exec.d.ts +4 -4
- package/dist/agent-core/tools/local/exec.js +234 -62
- package/dist/agent-core/tools/local/registry.d.ts +6 -0
- package/dist/agent-core/tools/local/registry.js +60 -9
- package/dist/agent-core/tools/local/view-image.js +108 -2
- package/dist/agent-core/tools/mcp/catalog.d.ts +6 -2
- package/dist/agent-core/tools/mcp/catalog.js +4 -4
- package/dist/agent-core/tools/mcp/history.js +2 -2
- package/dist/agent-core/tools/mcp/tool-search.d.ts +3 -1
- package/dist/agent-core/tools/mcp/tool-search.js +2 -2
- package/dist/agent-core/tools/output-projection.d.ts +3 -1
- package/dist/agent-core/tools/output-projection.js +11 -2
- package/dist/agent-core/tools/runtime-context.d.ts +1 -0
- package/dist/agent-core/tools/runtime.d.ts +3 -1
- package/dist/agent-core/tools/runtime.js +22 -7
- package/dist/agent-core/tools/scheduler.d.ts +2 -0
- package/dist/agent-core/tools/scheduler.js +43 -6
- package/dist/index.d.ts +21 -0
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +5 -2
- package/package.json +1 -1
|
@@ -7,7 +7,9 @@ import WebSocket from 'ws';
|
|
|
7
7
|
import { isRetryableUpstreamOverloadCode, number, parseSse, record, text, observeModelStreamEvent, modelStreamEventObservedAt } from './sse.js';
|
|
8
8
|
import { connectSocks5Target, fetchModelResponse, isRetryableModelHttpStatus, isRetryableModelTransportError, modelRetryMaxAttempts, isRetryableModelRequestError, modelRetryDelay, waitForModelRetry } from './http.js';
|
|
9
9
|
import { acquireModelCredential, appendModelCredentialHeaders } from './runtime-credential.js';
|
|
10
|
+
import { resolveModelTextBlocks } from './text-blocks.js';
|
|
10
11
|
const WEBSOCKET_IDLE_TIMEOUT_MS = 300_000;
|
|
12
|
+
const WEBSOCKET_SEND_FRAME_BYTES = 1024 * 1024;
|
|
11
13
|
export const OPENAI_RESPONSES_EARLY_EOF_REASON = 'OPENAI_RESPONSES_EARLY_EOF';
|
|
12
14
|
export const OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT_REASON = 'OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT';
|
|
13
15
|
const X_CODEX_TURN_STATE = 'x-codex-turn-state';
|
|
@@ -624,6 +626,7 @@ class OpenAiResponsesTurnSession {
|
|
|
624
626
|
#fullBody;
|
|
625
627
|
#completedResponseId;
|
|
626
628
|
#connectionDiagnostic;
|
|
629
|
+
#webSocketDiagnostic;
|
|
627
630
|
constructor(adapter, state, cacheLease) {
|
|
628
631
|
this.adapter = adapter;
|
|
629
632
|
this.state = state;
|
|
@@ -735,9 +738,13 @@ class OpenAiResponsesTurnSession {
|
|
|
735
738
|
}
|
|
736
739
|
beginAttempt() {
|
|
737
740
|
this.#connectionDiagnostic = undefined;
|
|
741
|
+
this.#webSocketDiagnostic = undefined;
|
|
742
|
+
}
|
|
743
|
+
captureWebSocketDiagnostic(diagnostic) {
|
|
744
|
+
this.#webSocketDiagnostic = diagnostic;
|
|
738
745
|
}
|
|
739
746
|
connectionDiagnostic() {
|
|
740
|
-
return this.#connectionDiagnostic
|
|
747
|
+
return { ...this.#connectionDiagnostic, ...this.#webSocketDiagnostic };
|
|
741
748
|
}
|
|
742
749
|
captureTurnState(value) {
|
|
743
750
|
if (this.#turnState !== undefined || typeof value !== 'string')
|
|
@@ -855,6 +862,11 @@ function isLocalContinuationReset(error) {
|
|
|
855
862
|
return error instanceof MarAgentError && error.code === 'MAR_AGENT_RESPONSES_CONTINUATION_RESET';
|
|
856
863
|
}
|
|
857
864
|
function responsesRequestBody(configuration, request, messages) {
|
|
865
|
+
if ((request.systemBlocks !== undefined &&
|
|
866
|
+
resolveModelTextBlocks(request.system, request.systemBlocks).some((block) => block.cache)) ||
|
|
867
|
+
messages.some((message) => message.textBlocks !== undefined &&
|
|
868
|
+
resolveModelTextBlocks(message.content, message.textBlocks).some((block) => block.cache)))
|
|
869
|
+
throw new MarAgentError('MAR_AGENT_MODEL_CAPABILITY_UNAVAILABLE', 'This model protocol does not support explicit text-block cache markers.');
|
|
858
870
|
const tools = request.allowTools === false
|
|
859
871
|
? []
|
|
860
872
|
: request.tools.map((tool) => tool.nativeType === 'tool_search'
|
|
@@ -881,14 +893,27 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
881
893
|
tools.push({ type: 'web_search' });
|
|
882
894
|
const toolChoice = request.toolChoice ?? 'auto';
|
|
883
895
|
const input = openAiInput(messages, request.images, configuration.id, true, usesResponsesConfigurationUpdates(configuration));
|
|
896
|
+
if (request.systemBlocks !== undefined && (request.systemBlocks.length || request.system.length))
|
|
897
|
+
input.unshift({
|
|
898
|
+
role: 'developer',
|
|
899
|
+
content: resolveModelTextBlocks(request.system, request.systemBlocks).map((block) => ({
|
|
900
|
+
type: 'input_text',
|
|
901
|
+
text: block.text
|
|
902
|
+
}))
|
|
903
|
+
});
|
|
884
904
|
return {
|
|
885
905
|
model: configuration.modelId,
|
|
906
|
+
...(request.outputLimit === undefined
|
|
907
|
+
? {}
|
|
908
|
+
: {
|
|
909
|
+
max_output_tokens: Math.min(request.outputLimit, configuration.maxOutputTokens)
|
|
910
|
+
}),
|
|
886
911
|
...(configuration.serviceTier !== undefined
|
|
887
912
|
? { service_tier: configuration.serviceTier }
|
|
888
913
|
: configuration.fastMode === true
|
|
889
914
|
? { service_tier: 'priority' }
|
|
890
915
|
: {}),
|
|
891
|
-
instructions: request.system,
|
|
916
|
+
instructions: request.systemBlocks === undefined ? request.system : '',
|
|
892
917
|
tools,
|
|
893
918
|
tool_choice: toolChoice,
|
|
894
919
|
input,
|
|
@@ -933,6 +958,7 @@ function responsesContinuationPropertiesMatch(previous, current) {
|
|
|
933
958
|
'instructions',
|
|
934
959
|
'tools',
|
|
935
960
|
'tool_choice',
|
|
961
|
+
'max_output_tokens',
|
|
936
962
|
'parallel_tool_calls',
|
|
937
963
|
'reasoning',
|
|
938
964
|
'store',
|
|
@@ -1010,6 +1036,10 @@ async function* parseOpenAiResponsesSse(response, signal, continuation) {
|
|
|
1010
1036
|
}
|
|
1011
1037
|
}
|
|
1012
1038
|
async function* webSocketResponseEvents(input) {
|
|
1039
|
+
const body = input.turn.withTurnStateMetadata(input.body);
|
|
1040
|
+
const payload = Buffer.from(JSON.stringify({ type: 'response.create', ...body }), 'utf8');
|
|
1041
|
+
const diagnostic = webSocketRequestDiagnostic(body, payload.length);
|
|
1042
|
+
input.turn.captureWebSocketDiagnostic(diagnostic);
|
|
1013
1043
|
const socket = await input.turn.webSocketForRequest({
|
|
1014
1044
|
configuration: input.configuration,
|
|
1015
1045
|
promptCacheKey: input.promptCacheKey,
|
|
@@ -1018,32 +1048,75 @@ async function* webSocketResponseEvents(input) {
|
|
|
1018
1048
|
continuation: input.continuation,
|
|
1019
1049
|
credentialAcquired: input.credentialAcquired
|
|
1020
1050
|
});
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
type
|
|
1034
|
-
|
|
1035
|
-
|
|
1051
|
+
const messages = webSocketMessages(socket, input.signal, (code) => {
|
|
1052
|
+
diagnostic.webSocketCloseCode = code;
|
|
1053
|
+
});
|
|
1054
|
+
try {
|
|
1055
|
+
diagnostic.webSocketPhase = 'SEND';
|
|
1056
|
+
await sendWebSocketMessage(socket, payload, input.signal, () => {
|
|
1057
|
+
diagnostic.sentFrameCount = (diagnostic.sentFrameCount ?? 0) + 1;
|
|
1058
|
+
});
|
|
1059
|
+
diagnostic.webSocketPhase = 'RECEIVE';
|
|
1060
|
+
let terminal = false;
|
|
1061
|
+
for await (const item of messages) {
|
|
1062
|
+
const event = record(item);
|
|
1063
|
+
const type = text(event.type);
|
|
1064
|
+
input.turn.captureTurnState(turnStateFromEvent(event));
|
|
1065
|
+
if (type !== 'response.metadata' && type !== 'codex.response.metadata')
|
|
1066
|
+
yield item;
|
|
1067
|
+
if (type === 'response.completed' ||
|
|
1068
|
+
type === 'response.incomplete' ||
|
|
1069
|
+
type === 'response.failed' ||
|
|
1070
|
+
type === 'error') {
|
|
1071
|
+
terminal = true;
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1036
1074
|
}
|
|
1075
|
+
if (!terminal && !input.signal.aborted)
|
|
1076
|
+
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'OpenAI Responses WebSocket closed before a terminal event.', {
|
|
1077
|
+
details: {
|
|
1078
|
+
reason: OPENAI_RESPONSES_EARLY_EOF_REASON,
|
|
1079
|
+
transport: 'WEBSOCKET',
|
|
1080
|
+
continuation: input.continuation
|
|
1081
|
+
},
|
|
1082
|
+
retryable: true
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
finally {
|
|
1086
|
+
messages.dispose();
|
|
1037
1087
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1088
|
+
}
|
|
1089
|
+
function webSocketRequestDiagnostic(body, requestBytes) {
|
|
1090
|
+
let imageCount = 0;
|
|
1091
|
+
let imageBytes = 0;
|
|
1092
|
+
for (const item of body.input) {
|
|
1093
|
+
const entry = record(item);
|
|
1094
|
+
const parts = Array.isArray(entry.content)
|
|
1095
|
+
? entry.content
|
|
1096
|
+
: Array.isArray(entry.output)
|
|
1097
|
+
? entry.output
|
|
1098
|
+
: [];
|
|
1099
|
+
for (const value of parts) {
|
|
1100
|
+
const part = record(value);
|
|
1101
|
+
if (part.type !== 'input_image')
|
|
1102
|
+
continue;
|
|
1103
|
+
imageCount++;
|
|
1104
|
+
const url = text(part.image_url);
|
|
1105
|
+
if (url === undefined)
|
|
1106
|
+
continue;
|
|
1107
|
+
const marker = url.indexOf(';base64,');
|
|
1108
|
+
if (url.startsWith('data:') && marker >= 0)
|
|
1109
|
+
imageBytes += Buffer.byteLength(url.slice(marker + 8), 'base64');
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return {
|
|
1113
|
+
requestBytes,
|
|
1114
|
+
imageCount,
|
|
1115
|
+
imageBytes,
|
|
1116
|
+
requestFrameCount: Math.ceil(requestBytes / WEBSOCKET_SEND_FRAME_BYTES),
|
|
1117
|
+
sentFrameCount: 0,
|
|
1118
|
+
webSocketPhase: 'CONNECT'
|
|
1119
|
+
};
|
|
1047
1120
|
}
|
|
1048
1121
|
async function waitForWebSocketOpen(socket, signal) {
|
|
1049
1122
|
if (signal.aborted) {
|
|
@@ -1101,29 +1174,55 @@ async function waitForWebSocketOpen(socket, signal) {
|
|
|
1101
1174
|
socket.once('unexpected-response', unexpectedResponse);
|
|
1102
1175
|
});
|
|
1103
1176
|
}
|
|
1104
|
-
async function sendWebSocketMessage(socket,
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
cleanup()
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1177
|
+
async function sendWebSocketMessage(socket, payload, signal, frameSent) {
|
|
1178
|
+
for (let offset = 0; offset < payload.length; offset += WEBSOCKET_SEND_FRAME_BYTES) {
|
|
1179
|
+
if (signal.aborted)
|
|
1180
|
+
throw signal.reason;
|
|
1181
|
+
const end = Math.min(payload.length, offset + WEBSOCKET_SEND_FRAME_BYTES);
|
|
1182
|
+
await new Promise((resolve, reject) => {
|
|
1183
|
+
let settled = false;
|
|
1184
|
+
const cleanup = () => {
|
|
1185
|
+
settled = true;
|
|
1186
|
+
signal.removeEventListener('abort', abort);
|
|
1187
|
+
socket.off('error', error);
|
|
1188
|
+
socket.off('close', close);
|
|
1189
|
+
};
|
|
1190
|
+
const abort = () => {
|
|
1191
|
+
cleanup();
|
|
1192
|
+
socket.terminate();
|
|
1120
1193
|
reject(signal.reason);
|
|
1121
|
-
|
|
1122
|
-
|
|
1194
|
+
};
|
|
1195
|
+
const error = (cause) => {
|
|
1196
|
+
cleanup();
|
|
1197
|
+
reject(webSocketReceiveError(cause));
|
|
1198
|
+
};
|
|
1199
|
+
const close = () => error(new Error('WebSocket closed while sending the request.'));
|
|
1200
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
1201
|
+
socket.once('error', error);
|
|
1202
|
+
socket.once('close', close);
|
|
1203
|
+
try {
|
|
1204
|
+
socket.send(payload.subarray(offset, end), { binary: false, fin: end === payload.length }, (cause) => {
|
|
1205
|
+
if (settled)
|
|
1206
|
+
return;
|
|
1207
|
+
cleanup();
|
|
1208
|
+
if (cause)
|
|
1209
|
+
reject(webSocketReceiveError(cause));
|
|
1210
|
+
else if (signal.aborted)
|
|
1211
|
+
reject(signal.reason);
|
|
1212
|
+
else {
|
|
1213
|
+
frameSent();
|
|
1214
|
+
resolve();
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
catch (cause) {
|
|
1219
|
+
cleanup();
|
|
1220
|
+
reject(webSocketReceiveError(cause));
|
|
1221
|
+
}
|
|
1123
1222
|
});
|
|
1124
|
-
}
|
|
1223
|
+
}
|
|
1125
1224
|
}
|
|
1126
|
-
|
|
1225
|
+
function webSocketMessages(socket, signal, closed) {
|
|
1127
1226
|
const queue = [];
|
|
1128
1227
|
let resume;
|
|
1129
1228
|
const push = (item) => {
|
|
@@ -1136,7 +1235,10 @@ async function* webSocketMessages(socket, signal) {
|
|
|
1136
1235
|
value,
|
|
1137
1236
|
observedAt: performance.now()
|
|
1138
1237
|
});
|
|
1139
|
-
const close = () =>
|
|
1238
|
+
const close = (code) => {
|
|
1239
|
+
closed(code);
|
|
1240
|
+
push({ type: 'closed' });
|
|
1241
|
+
};
|
|
1140
1242
|
const error = (cause) => push({
|
|
1141
1243
|
type: 'error',
|
|
1142
1244
|
error: webSocketReceiveError(cause)
|
|
@@ -1153,49 +1255,57 @@ async function* webSocketMessages(socket, signal) {
|
|
|
1153
1255
|
socket.on('close', close);
|
|
1154
1256
|
socket.on('error', error);
|
|
1155
1257
|
signal.addEventListener('abort', abort, { once: true });
|
|
1156
|
-
|
|
1157
|
-
let idleDeadline = Date.now() + WEBSOCKET_IDLE_TIMEOUT_MS;
|
|
1158
|
-
while (true) {
|
|
1159
|
-
if (Date.now() >= idleDeadline)
|
|
1160
|
-
throw webSocketIdleError(socket);
|
|
1161
|
-
if (queue.length === 0)
|
|
1162
|
-
await new Promise((resolve, reject) => {
|
|
1163
|
-
const timer = setTimeout(() => {
|
|
1164
|
-
resume = undefined;
|
|
1165
|
-
reject(webSocketIdleError(socket));
|
|
1166
|
-
}, Math.max(0, idleDeadline - Date.now()));
|
|
1167
|
-
resume = () => {
|
|
1168
|
-
clearTimeout(timer);
|
|
1169
|
-
resolve();
|
|
1170
|
-
};
|
|
1171
|
-
});
|
|
1172
|
-
const item = queue.shift();
|
|
1173
|
-
if (item === undefined)
|
|
1174
|
-
continue;
|
|
1175
|
-
if (item.type === 'closed')
|
|
1176
|
-
return;
|
|
1177
|
-
if (item.type === 'error')
|
|
1178
|
-
throw item.error;
|
|
1179
|
-
const text = await webSocketMessageText(item.value);
|
|
1180
|
-
if (Buffer.byteLength(text) > 16 * 1024 * 1024)
|
|
1181
|
-
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Model response exceeded the size limit.');
|
|
1182
|
-
try {
|
|
1183
|
-
const event = JSON.parse(text);
|
|
1184
|
-
if (!isWebSocketNonProgressEvent(event))
|
|
1185
|
-
idleDeadline = Date.now() + WEBSOCKET_IDLE_TIMEOUT_MS;
|
|
1186
|
-
yield observeModelStreamEvent(event, item.observedAt);
|
|
1187
|
-
}
|
|
1188
|
-
catch (cause) {
|
|
1189
|
-
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Model WebSocket contained invalid JSON.', { cause });
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
finally {
|
|
1258
|
+
const dispose = () => {
|
|
1194
1259
|
signal.removeEventListener('abort', abort);
|
|
1195
1260
|
socket.off('message', message);
|
|
1196
1261
|
socket.off('close', close);
|
|
1197
1262
|
socket.off('error', error);
|
|
1198
|
-
}
|
|
1263
|
+
};
|
|
1264
|
+
return {
|
|
1265
|
+
dispose,
|
|
1266
|
+
async *[Symbol.asyncIterator]() {
|
|
1267
|
+
try {
|
|
1268
|
+
let idleDeadline = Date.now() + WEBSOCKET_IDLE_TIMEOUT_MS;
|
|
1269
|
+
while (true) {
|
|
1270
|
+
if (Date.now() >= idleDeadline)
|
|
1271
|
+
throw webSocketIdleError(socket);
|
|
1272
|
+
if (queue.length === 0)
|
|
1273
|
+
await new Promise((resolve, reject) => {
|
|
1274
|
+
const timer = setTimeout(() => {
|
|
1275
|
+
resume = undefined;
|
|
1276
|
+
reject(webSocketIdleError(socket));
|
|
1277
|
+
}, Math.max(0, idleDeadline - Date.now()));
|
|
1278
|
+
resume = () => {
|
|
1279
|
+
clearTimeout(timer);
|
|
1280
|
+
resolve();
|
|
1281
|
+
};
|
|
1282
|
+
});
|
|
1283
|
+
const item = queue.shift();
|
|
1284
|
+
if (item === undefined)
|
|
1285
|
+
continue;
|
|
1286
|
+
if (item.type === 'closed')
|
|
1287
|
+
return;
|
|
1288
|
+
if (item.type === 'error')
|
|
1289
|
+
throw item.error;
|
|
1290
|
+
const text = await webSocketMessageText(item.value);
|
|
1291
|
+
if (Buffer.byteLength(text) > 16 * 1024 * 1024)
|
|
1292
|
+
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Model response exceeded the size limit.');
|
|
1293
|
+
try {
|
|
1294
|
+
const event = JSON.parse(text);
|
|
1295
|
+
if (!isWebSocketNonProgressEvent(event))
|
|
1296
|
+
idleDeadline = Date.now() + WEBSOCKET_IDLE_TIMEOUT_MS;
|
|
1297
|
+
yield observeModelStreamEvent(event, item.observedAt);
|
|
1298
|
+
}
|
|
1299
|
+
catch (cause) {
|
|
1300
|
+
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Model WebSocket contained invalid JSON.', { cause });
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
finally {
|
|
1305
|
+
dispose();
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1199
1309
|
}
|
|
1200
1310
|
function webSocketIdleError(socket) {
|
|
1201
1311
|
terminateWebSocket(socket);
|
|
@@ -1597,8 +1707,8 @@ function strictFunctionSchema(value, optional = false) {
|
|
|
1597
1707
|
return value;
|
|
1598
1708
|
const schema = value;
|
|
1599
1709
|
const supportedSchema = Object.fromEntries(Object.entries(schema).filter(([keyword]) => keyword !== 'propertyNames'));
|
|
1600
|
-
if (schema.type === 'object'
|
|
1601
|
-
const properties = schema.properties;
|
|
1710
|
+
if (schema.type === 'object') {
|
|
1711
|
+
const properties = record(schema.properties);
|
|
1602
1712
|
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
1603
1713
|
return {
|
|
1604
1714
|
...supportedSchema,
|
|
@@ -1771,40 +1881,81 @@ function openAiInputItem(message, images, customCallIds = new Set(), functionCal
|
|
|
1771
1881
|
type: 'input_image',
|
|
1772
1882
|
image_url: `data:${part.image.mimeType};base64,${part.image.dataBase64}`
|
|
1773
1883
|
}) ??
|
|
1774
|
-
(message.
|
|
1884
|
+
(message.textBlocks !== undefined
|
|
1775
1885
|
? [
|
|
1776
|
-
|
|
1777
|
-
|
|
1886
|
+
...resolveModelTextBlocks(message.content, message.textBlocks).map((block) => ({
|
|
1887
|
+
type: 'input_text',
|
|
1888
|
+
text: block.text
|
|
1889
|
+
})),
|
|
1890
|
+
...(message.images ?? []).map((image) => ({
|
|
1778
1891
|
type: 'input_image',
|
|
1779
1892
|
image_url: `data:${image.mimeType};base64,${image.dataBase64}`
|
|
1780
1893
|
}))
|
|
1781
1894
|
]
|
|
1782
|
-
: message.
|
|
1895
|
+
: message.images?.length
|
|
1896
|
+
? [
|
|
1897
|
+
{ type: 'input_text', text: message.content },
|
|
1898
|
+
...message.images.map((image) => ({
|
|
1899
|
+
type: 'input_image',
|
|
1900
|
+
image_url: `data:${image.mimeType};base64,${image.dataBase64}`
|
|
1901
|
+
}))
|
|
1902
|
+
]
|
|
1903
|
+
: message.content)
|
|
1783
1904
|
};
|
|
1784
1905
|
return {
|
|
1785
1906
|
role: message.role,
|
|
1786
|
-
content:
|
|
1907
|
+
content: message.textBlocks !== undefined
|
|
1787
1908
|
? [
|
|
1788
|
-
|
|
1909
|
+
...resolveModelTextBlocks(message.content, message.textBlocks).map((block) => ({
|
|
1910
|
+
type: message.role === 'assistant' ? 'output_text' : 'input_text',
|
|
1911
|
+
text: block.text
|
|
1912
|
+
})),
|
|
1789
1913
|
...userImages.map((image) => ({
|
|
1790
1914
|
type: 'input_image',
|
|
1791
1915
|
image_url: `data:${image.mimeType};base64,${image.dataBase64}`
|
|
1792
1916
|
}))
|
|
1793
1917
|
]
|
|
1794
|
-
:
|
|
1918
|
+
: userImages.length > 0
|
|
1919
|
+
? [
|
|
1920
|
+
{ type: 'input_text', text: message.content },
|
|
1921
|
+
...userImages.map((image) => ({
|
|
1922
|
+
type: 'input_image',
|
|
1923
|
+
image_url: `data:${image.mimeType};base64,${image.dataBase64}`
|
|
1924
|
+
}))
|
|
1925
|
+
]
|
|
1926
|
+
: message.content
|
|
1795
1927
|
};
|
|
1796
1928
|
}
|
|
1797
1929
|
function responsesFunctionTool(tool) {
|
|
1930
|
+
const strict = !hasOpenFunctionObject(tool.inputSchema);
|
|
1798
1931
|
return tool.inputMode === 'freeform'
|
|
1799
1932
|
? { type: 'custom', name: tool.name, description: tool.description }
|
|
1800
1933
|
: {
|
|
1801
1934
|
type: 'function',
|
|
1802
1935
|
name: tool.name,
|
|
1803
1936
|
description: tool.description,
|
|
1804
|
-
parameters: strictFunctionSchema(tool.inputSchema),
|
|
1805
|
-
strict
|
|
1937
|
+
parameters: strict ? strictFunctionSchema(tool.inputSchema) : tool.inputSchema,
|
|
1938
|
+
strict
|
|
1806
1939
|
};
|
|
1807
1940
|
}
|
|
1941
|
+
function hasOpenFunctionObject(value) {
|
|
1942
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
1943
|
+
return false;
|
|
1944
|
+
const schema = record(value);
|
|
1945
|
+
if ((schema.type === 'object' || (Array.isArray(schema.type) && schema.type.includes('object'))) &&
|
|
1946
|
+
(schema.additionalProperties === true ||
|
|
1947
|
+
(schema.additionalProperties !== null && typeof schema.additionalProperties === 'object') ||
|
|
1948
|
+
(schema.properties === undefined && schema.additionalProperties !== false)))
|
|
1949
|
+
return true;
|
|
1950
|
+
const children = [
|
|
1951
|
+
...Object.values(record(schema.properties)),
|
|
1952
|
+
...Object.values(record(schema.$defs)),
|
|
1953
|
+
...Object.values(record(schema.definitions)),
|
|
1954
|
+
schema.items,
|
|
1955
|
+
...[schema.anyOf, schema.oneOf, schema.allOf].flatMap((items) => Array.isArray(items) ? items : [])
|
|
1956
|
+
];
|
|
1957
|
+
return children.some(hasOpenFunctionObject);
|
|
1958
|
+
}
|
|
1808
1959
|
function uniqueModelImages(...groups) {
|
|
1809
1960
|
const seen = new Set();
|
|
1810
1961
|
return groups.flatMap((group) => (group ?? []).flatMap((image) => {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ModelTextBlock } from './contracts.js';
|
|
2
|
+
/** Preserve explicit blocks only while their complete texts still match the actual prefix. */
|
|
3
|
+
export declare function resolveModelTextBlocks(text: string, blocks: readonly ModelTextBlock[]): readonly ModelTextBlock[];
|
|
4
|
+
export declare function modelTextInput(value: string | readonly ModelTextBlock[]): {
|
|
5
|
+
text: string;
|
|
6
|
+
blocks?: readonly ModelTextBlock[];
|
|
7
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MarAgentError } from '../error.js';
|
|
2
|
+
/** Preserve explicit blocks only while their complete texts still match the actual prefix. */
|
|
3
|
+
export function resolveModelTextBlocks(text, blocks) {
|
|
4
|
+
if (typeof text !== 'string' || !Array.isArray(blocks))
|
|
5
|
+
throw invalid();
|
|
6
|
+
const copied = blocks.map((block) => {
|
|
7
|
+
if (!block ||
|
|
8
|
+
typeof block !== 'object' ||
|
|
9
|
+
typeof block.text !== 'string' ||
|
|
10
|
+
(block.cache !== undefined && block.cache !== true))
|
|
11
|
+
throw invalid();
|
|
12
|
+
return { text: block.text, ...(block.cache === true ? { cache: true } : {}) };
|
|
13
|
+
});
|
|
14
|
+
let offset = 0;
|
|
15
|
+
const result = [];
|
|
16
|
+
for (const block of copied) {
|
|
17
|
+
if (!text.startsWith(block.text, offset))
|
|
18
|
+
break;
|
|
19
|
+
result.push(block);
|
|
20
|
+
offset += block.text.length;
|
|
21
|
+
}
|
|
22
|
+
if (offset < text.length)
|
|
23
|
+
result.push({ text: text.slice(offset) });
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
export function modelTextInput(value) {
|
|
27
|
+
if (typeof value === 'string')
|
|
28
|
+
return { text: value };
|
|
29
|
+
if (!Array.isArray(value))
|
|
30
|
+
throw invalid();
|
|
31
|
+
for (const block of value) {
|
|
32
|
+
if (!block || typeof block !== 'object' || typeof block.text !== 'string')
|
|
33
|
+
throw invalid();
|
|
34
|
+
}
|
|
35
|
+
const text = value.map((block) => block.text).join('');
|
|
36
|
+
return { text, blocks: resolveModelTextBlocks(text, value) };
|
|
37
|
+
}
|
|
38
|
+
function invalid() {
|
|
39
|
+
return new MarAgentError('MAR_AGENT_MODEL_TEXT_BLOCK_INVALID', 'Model text blocks are invalid.');
|
|
40
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExecutionMode } from '../runtime/contracts.js';
|
|
2
|
+
import { type CorePromptPart } from '../extensions/prompt-composition.js';
|
|
2
3
|
export declare const MAR_AGENT_PROMPT_VERSION = "1.60";
|
|
3
|
-
|
|
4
|
+
interface SystemPromptInput {
|
|
4
5
|
mode: ExecutionMode;
|
|
5
6
|
platform: string;
|
|
6
7
|
architecture?: string;
|
|
@@ -14,4 +15,7 @@ export declare function buildSystemPrompt(input: {
|
|
|
14
15
|
directTools?: readonly string[];
|
|
15
16
|
highDensityCompaction?: boolean;
|
|
16
17
|
extension?: string | undefined;
|
|
17
|
-
}
|
|
18
|
+
}
|
|
19
|
+
export declare function buildSystemPrompt(input: SystemPromptInput): string;
|
|
20
|
+
export declare function buildSystemPromptSections(input: SystemPromptInput): readonly CorePromptPart[];
|
|
21
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderPromptSections } from '../extensions/prompt-composition.js';
|
|
1
2
|
import { compactionPrompt, highDensityCompactionPrompt } from './compact.js';
|
|
2
3
|
import { environmentPrompt, identityPrompt, instructionPriorityPrompt, workspaceDisciplinePrompt } from './core.js';
|
|
3
4
|
import { modePrompt } from './modes.js';
|
|
@@ -6,6 +7,9 @@ import { subagentPrompt } from './subagent.js';
|
|
|
6
7
|
import { interactionPrompt, longRunningPrompt, safetyPrompt, toolUsagePrompt, workflowPrompt } from './workflow.js';
|
|
7
8
|
export const MAR_AGENT_PROMPT_VERSION = '1.60';
|
|
8
9
|
export function buildSystemPrompt(input) {
|
|
10
|
+
return renderPromptSections(buildSystemPromptSections(input));
|
|
11
|
+
}
|
|
12
|
+
export function buildSystemPromptSections(input) {
|
|
9
13
|
const toolNames = new Set(input.tools);
|
|
10
14
|
const hasLongRunningCapability = [
|
|
11
15
|
'exec',
|
|
@@ -15,28 +19,38 @@ export function buildSystemPrompt(input) {
|
|
|
15
19
|
'agent_wait',
|
|
16
20
|
'agent_cancel'
|
|
17
21
|
].some((name) => toolNames.has(name));
|
|
18
|
-
|
|
19
|
-
identityPrompt(),
|
|
20
|
-
instructionPriorityPrompt,
|
|
21
|
-
workspaceDisciplinePrompt,
|
|
22
|
-
workflowPrompt,
|
|
23
|
-
interactionPrompt,
|
|
24
|
-
safetyPrompt,
|
|
25
|
-
outputStylePrompt,
|
|
26
|
-
environmentPrompt(input),
|
|
27
|
-
input.tools.length > 0 ? toolUsagePrompt(input.tools, input.directTools) : '',
|
|
28
|
-
hasLongRunningCapability ? longRunningPrompt(input.tools) : '',
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
22
|
+
const values = [
|
|
23
|
+
['identity', identityPrompt()],
|
|
24
|
+
['instruction-priority', instructionPriorityPrompt],
|
|
25
|
+
['workspace-discipline', workspaceDisciplinePrompt],
|
|
26
|
+
['workflow', workflowPrompt],
|
|
27
|
+
['interaction', interactionPrompt],
|
|
28
|
+
['safety', safetyPrompt],
|
|
29
|
+
['output-style', outputStylePrompt],
|
|
30
|
+
['environment-rules', environmentPrompt(input)],
|
|
31
|
+
['tools', input.tools.length > 0 ? toolUsagePrompt(input.tools, input.directTools) : ''],
|
|
32
|
+
['long-running', hasLongRunningCapability ? longRunningPrompt(input.tools) : ''],
|
|
33
|
+
[
|
|
34
|
+
'mode',
|
|
35
|
+
modePrompt(input.mode, {
|
|
36
|
+
questionAvailable: toolNames.has('question')
|
|
37
|
+
})
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
'compaction',
|
|
41
|
+
input.mode === 'compact'
|
|
42
|
+
? input.highDensityCompaction
|
|
43
|
+
? highDensityCompactionPrompt()
|
|
44
|
+
: compactionPrompt()
|
|
45
|
+
: ''
|
|
46
|
+
],
|
|
47
|
+
['subagent', toolNames.has('agent_start') ? subagentPrompt : ''],
|
|
48
|
+
[
|
|
49
|
+
'caller-instructions',
|
|
50
|
+
input.extension
|
|
51
|
+
? `# Caller, project, and selected Skill instructions\n${input.extension}`
|
|
52
|
+
: ''
|
|
53
|
+
]
|
|
54
|
+
];
|
|
55
|
+
return Object.freeze(values.map(([id, text]) => Object.freeze({ id: `core:${id}`, text: text || null })));
|
|
42
56
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { openAiInput } from '../../model/openai-responses.js';
|
|
2
2
|
import { countModelTokens } from '../token-budget.js';
|
|
3
|
+
import { observationModelText } from '../../tools/code-mode/observations.js';
|
|
3
4
|
export { MODEL_TOKEN_ESTIMATOR as CONTEXT_GC_TOKEN_ESTIMATOR } from '../token-budget.js';
|
|
4
5
|
/** Uses Responses lowering, including native alias and cross-model filtering. */
|
|
5
6
|
export function contextGcTokenEntries(input, messages) {
|
|
@@ -17,7 +18,11 @@ function serializedEntries(input, messages) {
|
|
|
17
18
|
: messages
|
|
18
19
|
.filter((message) => message.role !== 'provider' ||
|
|
19
20
|
(message.provider === 'ANTHROPIC_MESSAGES' && message.providerModelId === input.modelId))
|
|
20
|
-
.map((
|
|
21
|
+
.map((original) => {
|
|
22
|
+
const { observations: _observations, observationId: _observationId, ...message } = original;
|
|
23
|
+
const content = original.role === 'tool' ? observationModelText(original) : undefined;
|
|
24
|
+
return content === undefined ? message : { ...message, content };
|
|
25
|
+
});
|
|
21
26
|
return values.map((value, index) => {
|
|
22
27
|
const item = value;
|
|
23
28
|
const callId = item.call_id ?? item.callId;
|