@agent-native/core 0.207.0 → 0.207.1-nightly-20261012011809
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/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.js +220 -45
- package/dist/agent/thread-message-projection.d.ts +3 -0
- package/dist/agent/thread-message-projection.js +136 -3
- package/dist/automation/index.d.ts +1 -1
- package/dist/chat-threads/store.d.ts +1 -0
- package/dist/chat-threads/store.js +14 -4
- package/dist/cli/connect.d.ts +1 -0
- package/dist/cli/connect.js +8 -3
- package/dist/client/chat/agentkit-agent-native.js +151 -77
- package/dist/client/chat/runtime.js +61 -2
- package/dist/client/onboarding/first-run-status.js +0 -4
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/mcp/agent-connected.d.ts +13 -0
- package/dist/mcp/agent-connected.js +63 -0
- package/dist/mcp/connect-app-label.d.ts +11 -0
- package/dist/mcp/connect-app-label.js +33 -0
- package/dist/mcp/connect-route.js +41 -33
- package/dist/mcp/connect-store.d.ts +6 -1
- package/dist/mcp/connect-store.js +10 -2
- package/dist/mcp/oauth-route.js +17 -5
- package/dist/mcp/oauth-store.d.ts +2 -0
- package/dist/mcp/oauth-store.js +5 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/index.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +5 -5
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/shared/mcp-connect-content.d.ts +1 -0
- package/dist/shared/mcp-connect-content.js +3 -0
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/tracking/registry.d.ts +1 -0
- package/dist/tracking/registry.js +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +7 -7
- package/docs/content/agent-native-toolkit.mdx +42 -38
- package/docs/content/components.mdx +29 -18
- package/docs/content/notifications.mdx +1 -1
- package/docs/content/progress.mdx +1 -1
- package/docs/content/sharing.mdx +1 -1
- package/docs/content/toolkit-agent-ux.mdx +17 -2
- package/docs/content/toolkit-command-navigation.mdx +4 -2
- package/docs/content/toolkit-comments-review.mdx +1 -1
- package/docs/content/toolkit-context-knowledge.mdx +14 -16
- package/docs/content/toolkit-editors-canvases.mdx +24 -7
- package/docs/content/toolkit-history.mdx +13 -26
- package/docs/content/toolkit-org-team.mdx +4 -4
- package/docs/content/toolkit-resources.mdx +3 -1
- package/docs/content/toolkit-settings.mdx +1 -1
- package/docs/content/toolkit-setup-connections.mdx +1 -1
- package/docs/content/toolkit-sharing.mdx +6 -6
- package/docs/content/toolkit-ui.mdx +11 -0
- package/package.json +4 -4
package/dist/cli/connect.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ export interface ConnectDeps {
|
|
|
57
57
|
}
|
|
58
58
|
export declare function runDeviceFlow(baseUrl: string, appSlug: string, clientArg: string, deps?: ConnectDeps, options?: {
|
|
59
59
|
fullCatalog?: boolean;
|
|
60
|
+
purpose?: "agent" | "credential";
|
|
60
61
|
}): Promise<{
|
|
61
62
|
token?: string;
|
|
62
63
|
mcpUrl: string;
|
package/dist/cli/connect.js
CHANGED
|
@@ -329,7 +329,7 @@ async function resolveHostedAppsFromPrompt(deps) {
|
|
|
329
329
|
return apps.filter((app) => selected.has(app.name));
|
|
330
330
|
}
|
|
331
331
|
function clientArgForDeviceFlow(clients) {
|
|
332
|
-
return clients.
|
|
332
|
+
return clients.join(",");
|
|
333
333
|
}
|
|
334
334
|
export function supportsRemoteMcpOAuth(client) {
|
|
335
335
|
return REMOTE_MCP_OAUTH_CLIENTS.has(client);
|
|
@@ -616,6 +616,7 @@ export async function runDeviceFlow(baseUrl, appSlug, clientArg, deps = {}, opti
|
|
|
616
616
|
client: clientArg,
|
|
617
617
|
app: appSlug,
|
|
618
618
|
...(options.fullCatalog ? { fullCatalog: true } : {}),
|
|
619
|
+
...(options.purpose ? { purpose: options.purpose } : {}),
|
|
619
620
|
});
|
|
620
621
|
if (status >= 200 && status < 300 && json?.device_code) {
|
|
621
622
|
start = json;
|
|
@@ -1637,7 +1638,9 @@ async function connectOne(rawUrl, parsed, clients, deps) {
|
|
|
1637
1638
|
try {
|
|
1638
1639
|
logOut("");
|
|
1639
1640
|
logOut(` Minting a publish token for the local Plans server (device flow)…`);
|
|
1640
|
-
const grant = await runDeviceFlow(baseUrl, appSlug, "codex", deps
|
|
1641
|
+
const grant = await runDeviceFlow(baseUrl, appSlug, "codex", deps, {
|
|
1642
|
+
purpose: "credential",
|
|
1643
|
+
});
|
|
1641
1644
|
if (grant?.token) {
|
|
1642
1645
|
publishToken = grant.token;
|
|
1643
1646
|
}
|
|
@@ -1781,7 +1784,9 @@ export async function runServiceTokenMint(parsed, deps = {}) {
|
|
|
1781
1784
|
logOut("");
|
|
1782
1785
|
logOut(` Creating org service token "${serviceName}" on ${baseUrl}`);
|
|
1783
1786
|
logOut(" First, verify it's you (the token will belong to your org)…");
|
|
1784
|
-
const grant = await runDeviceFlow(baseUrl, appSlug, "codex", deps
|
|
1787
|
+
const grant = await runDeviceFlow(baseUrl, appSlug, "codex", deps, {
|
|
1788
|
+
purpose: "credential",
|
|
1789
|
+
});
|
|
1785
1790
|
if (!grant?.token) {
|
|
1786
1791
|
logErr(" Could not authenticate (the server returned no bearer token).");
|
|
1787
1792
|
logErr(" Org service tokens require a deployed app with auth configured.");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentKitRunSlotBusyError } from "@agent-native/agentkit/client";
|
|
2
|
-
import { isAgentKitProtocolVersion, parseAgentQueuedMessage, parseAgentRunOptions, parseAgentThreadSnapshot, persistableFilePart, } from "@agent-native/agentkit/protocol";
|
|
3
|
-
import { projectRootAssistantMessages } from "../../agent/thread-message-projection.js";
|
|
2
|
+
import { agentEventSequenceEnd, isAgentKitProtocolVersion, parseAgentQueuedMessage, parseAgentRunOptions, parseAgentThreadSnapshot, persistableFilePart, } from "@agent-native/agentkit/protocol";
|
|
3
|
+
import { failedRunIdsWithError, isRenderedRunNotStartedNotice, projectRootAssistantMessages, } from "../../agent/thread-message-projection.js";
|
|
4
4
|
import { RUN_NOT_STARTED_METADATA_KEY, retryContextFromRequest, } from "../../shared/agent-chat-run-not-started.js";
|
|
5
5
|
import { assertNoInlineImageBytes, stripInlineBytes, } from "../../shared/inline-bytes.js";
|
|
6
6
|
import { agentEngineStatusUrlForChatApi, requireAgentEngineConfiguredForDispatch, } from "../agent-engine-readiness.js";
|
|
@@ -278,18 +278,6 @@ function storedMessages(value, now, fallbackTextFormat) {
|
|
|
278
278
|
];
|
|
279
279
|
});
|
|
280
280
|
}
|
|
281
|
-
/**
|
|
282
|
-
* The server answers a turn it refused before any run started with a durable
|
|
283
|
-
* notice and a failed run. The run renders as the recovery card, so showing the
|
|
284
|
-
* notice too would print the same failure twice.
|
|
285
|
-
*/
|
|
286
|
-
function isRenderedRunNotStartedNotice(message, failedRunIds) {
|
|
287
|
-
const metadata = asRecord(message.metadata);
|
|
288
|
-
return (message.role === "assistant" &&
|
|
289
|
-
asRecord(metadata?.custom)?.[RUN_NOT_STARTED_METADATA_KEY] === true &&
|
|
290
|
-
typeof metadata?.runId === "string" &&
|
|
291
|
-
failedRunIds.has(metadata.runId));
|
|
292
|
-
}
|
|
293
281
|
function sameUserPrompt(left, right) {
|
|
294
282
|
if (left.role !== "user" ||
|
|
295
283
|
right.role !== "user" ||
|
|
@@ -667,8 +655,15 @@ function reconcileDurableMessages(messages, durable, events, runs, toolCalls) {
|
|
|
667
655
|
});
|
|
668
656
|
const representedDurableAssistantIds = rootAssistantProjection.representedRootMessageIds;
|
|
669
657
|
const snapshotRunIdsByMessageId = rootAssistantProjection.snapshotRunIdsByMessageId;
|
|
658
|
+
const supersededSnapshotMessageIds = rootAssistantProjection.supersededSnapshotMessageIds;
|
|
670
659
|
const rootMessageIdsBySnapshotMessageId = new Map([...rootAssistantProjection.snapshotMessageIdsByRootMessageId].map(([rootId, snapshotId]) => [snapshotId, rootId]));
|
|
671
|
-
const
|
|
660
|
+
const snapshotUserIds = new Set(messages.flatMap((message) => message.role === "user" ? [message.id] : []));
|
|
661
|
+
const representedDurableUserIds = new Set([...submittedUsersByAgentKitMessageId].flatMap(([snapshotId, stored]) => stored && snapshotId !== stored.id && snapshotUserIds.has(snapshotId)
|
|
662
|
+
? [stored.id]
|
|
663
|
+
: []));
|
|
664
|
+
const deduplicatedMessages = messages.filter((message) => !(message.role === "user" && representedDurableUserIds.has(message.id)) &&
|
|
665
|
+
!representedDurableAssistantIds.has(message.id) &&
|
|
666
|
+
!supersededSnapshotMessageIds.has(message.id) &&
|
|
672
667
|
!supersededCompletedAssistantIds.has(message.id));
|
|
673
668
|
const representedSubmittedUserIds = new Set();
|
|
674
669
|
const storedUserBySnapshotId = new Map();
|
|
@@ -830,6 +825,13 @@ function reconcileDurableMessages(messages, durable, events, runs, toolCalls) {
|
|
|
830
825
|
}
|
|
831
826
|
}
|
|
832
827
|
const runId = snapshotRunId(message);
|
|
828
|
+
const sameRunRoot = runId ? durableByRun.get(runId) : undefined;
|
|
829
|
+
if (sameRunRoot &&
|
|
830
|
+
rootAssistantProjection.snapshotMessageIdsByRootMessageId.has(sameRunRoot.id) &&
|
|
831
|
+
rootAssistantProjection.snapshotMessageIdsByRootMessageId.get(sameRunRoot.id) !== message.id &&
|
|
832
|
+
!durableById.has(message.id)) {
|
|
833
|
+
return message;
|
|
834
|
+
}
|
|
833
835
|
const matched = durableById.get(message.id) ??
|
|
834
836
|
(runId ? durableByRun.get(runId) : undefined);
|
|
835
837
|
// An earlier run of a folded reply is completed with the continuation text
|
|
@@ -1135,77 +1137,162 @@ function persistedRetryRequestAttachments(value) {
|
|
|
1135
1137
|
];
|
|
1136
1138
|
});
|
|
1137
1139
|
}
|
|
1140
|
+
const MAX_PERSISTED_EVENT_OMISSION_RANGE = 256;
|
|
1141
|
+
const MAX_PERSISTED_EVENT_PREFIX_RANGES = 4_096;
|
|
1138
1142
|
function persistedHistoryEvents(events = []) {
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1143
|
+
const persisted = [];
|
|
1144
|
+
const seenRuns = new Set();
|
|
1145
|
+
let generatedPrefixRanges = 0;
|
|
1146
|
+
const lastOmissionByRun = new Map();
|
|
1147
|
+
for (const event of events) {
|
|
1148
|
+
if (!seenRuns.has(event.runId)) {
|
|
1149
|
+
seenRuns.add(event.runId);
|
|
1150
|
+
const prefixRangeCount = Math.ceil(Math.max(0, event.sequence - 1) / MAX_PERSISTED_EVENT_OMISSION_RANGE);
|
|
1151
|
+
if (generatedPrefixRanges + prefixRangeCount >
|
|
1152
|
+
MAX_PERSISTED_EVENT_PREFIX_RANGES) {
|
|
1153
|
+
throw new RangeError("Agent chat retained history prefix exceeds the supported omission range count.");
|
|
1154
|
+
}
|
|
1155
|
+
generatedPrefixRanges += prefixRangeCount;
|
|
1156
|
+
for (let firstSequence = 1; firstSequence < event.sequence; firstSequence += MAX_PERSISTED_EVENT_OMISSION_RANGE) {
|
|
1157
|
+
const lastSequence = Math.min(event.sequence - 1, firstSequence + MAX_PERSISTED_EVENT_OMISSION_RANGE - 1);
|
|
1158
|
+
const index = persisted.length;
|
|
1159
|
+
persisted.push({
|
|
1160
|
+
id: `persisted-history-prefix:${event.runId}:${firstSequence}`,
|
|
1161
|
+
threadId: event.threadId,
|
|
1162
|
+
runId: event.runId,
|
|
1163
|
+
sequence: firstSequence,
|
|
1164
|
+
occurredAt: event.occurredAt,
|
|
1165
|
+
type: "x-agent-native.persisted-event-omission-range",
|
|
1166
|
+
payload: {
|
|
1167
|
+
lastSequence,
|
|
1168
|
+
sourceType: "runtime_history_prefix",
|
|
1169
|
+
},
|
|
1170
|
+
});
|
|
1171
|
+
lastOmissionByRun.set(event.runId, {
|
|
1172
|
+
index,
|
|
1173
|
+
firstSequence,
|
|
1174
|
+
lastSequence,
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1141
1178
|
const base = () => {
|
|
1142
|
-
const sequence = (sequenceByRun.get(event.runId) ?? 0) + 1;
|
|
1143
|
-
sequenceByRun.set(event.runId, sequence);
|
|
1144
1179
|
return {
|
|
1145
1180
|
id: event.id,
|
|
1146
1181
|
threadId: event.threadId,
|
|
1147
1182
|
runId: event.runId,
|
|
1148
|
-
sequence,
|
|
1183
|
+
sequence: event.sequence,
|
|
1149
1184
|
occurredAt: event.occurredAt,
|
|
1150
1185
|
};
|
|
1151
1186
|
};
|
|
1152
1187
|
if (event.type === "run.started") {
|
|
1153
|
-
|
|
1188
|
+
persisted.push({ ...base(), type: event.type });
|
|
1189
|
+
lastOmissionByRun.delete(event.runId);
|
|
1190
|
+
continue;
|
|
1154
1191
|
}
|
|
1155
1192
|
if (event.type === "run.completed" || event.type === "run.cancelled") {
|
|
1156
|
-
|
|
1193
|
+
persisted.push({ ...base(), type: event.type });
|
|
1194
|
+
lastOmissionByRun.delete(event.runId);
|
|
1195
|
+
continue;
|
|
1157
1196
|
}
|
|
1158
1197
|
if (event.type === "run.failed") {
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1198
|
+
persisted.push({
|
|
1199
|
+
...base(),
|
|
1200
|
+
type: event.type,
|
|
1201
|
+
error: persistedError(event.error),
|
|
1202
|
+
});
|
|
1203
|
+
lastOmissionByRun.delete(event.runId);
|
|
1204
|
+
continue;
|
|
1162
1205
|
}
|
|
1163
1206
|
if (event.type === "run.status") {
|
|
1164
|
-
|
|
1207
|
+
persisted.push({ ...base(), type: event.type, status: event.status });
|
|
1208
|
+
lastOmissionByRun.delete(event.runId);
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
if (event.type === "x-agent-native.persisted-event-omission" ||
|
|
1212
|
+
event.type === "x-agent-native.persisted-event-omission-range") {
|
|
1213
|
+
const index = persisted.length;
|
|
1214
|
+
persisted.push(event);
|
|
1215
|
+
lastOmissionByRun.set(event.runId, {
|
|
1216
|
+
index,
|
|
1217
|
+
firstSequence: event.sequence,
|
|
1218
|
+
lastSequence: agentEventSequenceEnd(event),
|
|
1219
|
+
});
|
|
1220
|
+
continue;
|
|
1165
1221
|
}
|
|
1166
1222
|
if (event.type === "activity.started" ||
|
|
1167
1223
|
event.type === "activity.updated" ||
|
|
1168
1224
|
event.type === "activity.completed") {
|
|
1169
1225
|
const activity = event.activity;
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
: {}),
|
|
1185
|
-
},
|
|
1226
|
+
persisted.push({
|
|
1227
|
+
...base(),
|
|
1228
|
+
type: event.type,
|
|
1229
|
+
activity: {
|
|
1230
|
+
id: activity.id,
|
|
1231
|
+
kind: activity.kind,
|
|
1232
|
+
label: activity.label,
|
|
1233
|
+
status: activity.status,
|
|
1234
|
+
...(activity.runId ? { runId: activity.runId } : {}),
|
|
1235
|
+
...(activity.agentId ? { agentId: activity.agentId } : {}),
|
|
1236
|
+
...(activity.startedAt ? { startedAt: activity.startedAt } : {}),
|
|
1237
|
+
...(activity.completedAt
|
|
1238
|
+
? { completedAt: activity.completedAt }
|
|
1239
|
+
: {}),
|
|
1186
1240
|
},
|
|
1187
|
-
|
|
1241
|
+
});
|
|
1242
|
+
lastOmissionByRun.delete(event.runId);
|
|
1243
|
+
continue;
|
|
1188
1244
|
}
|
|
1189
1245
|
if (event.type === "message.completed" &&
|
|
1190
1246
|
event.message.role === "assistant") {
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
...(event.message.status ? { status: event.message.status } : {}),
|
|
1203
|
-
},
|
|
1247
|
+
persisted.push({
|
|
1248
|
+
...base(),
|
|
1249
|
+
type: event.type,
|
|
1250
|
+
message: {
|
|
1251
|
+
id: event.message.id,
|
|
1252
|
+
role: event.message.role,
|
|
1253
|
+
parts: event.message.parts.filter((part) => part.type === "text"),
|
|
1254
|
+
...(event.message.createdAt
|
|
1255
|
+
? { createdAt: event.message.createdAt }
|
|
1256
|
+
: {}),
|
|
1257
|
+
...(event.message.status ? { status: event.message.status } : {}),
|
|
1204
1258
|
},
|
|
1205
|
-
|
|
1259
|
+
});
|
|
1260
|
+
lastOmissionByRun.delete(event.runId);
|
|
1261
|
+
continue;
|
|
1206
1262
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1263
|
+
const previous = lastOmissionByRun.get(event.runId);
|
|
1264
|
+
if (previous &&
|
|
1265
|
+
event.sequence === previous.lastSequence + 1 &&
|
|
1266
|
+
event.sequence - previous.firstSequence + 1 <=
|
|
1267
|
+
MAX_PERSISTED_EVENT_OMISSION_RANGE) {
|
|
1268
|
+
const omitted = persisted[previous.index];
|
|
1269
|
+
if (omitted) {
|
|
1270
|
+
persisted[previous.index] = {
|
|
1271
|
+
...omitted,
|
|
1272
|
+
type: "x-agent-native.persisted-event-omission-range",
|
|
1273
|
+
payload: {
|
|
1274
|
+
...(asRecord("payload" in omitted ? omitted.payload : undefined) ??
|
|
1275
|
+
{}),
|
|
1276
|
+
lastSequence: event.sequence,
|
|
1277
|
+
},
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
previous.lastSequence = event.sequence;
|
|
1281
|
+
continue;
|
|
1282
|
+
}
|
|
1283
|
+
const index = persisted.length;
|
|
1284
|
+
persisted.push({
|
|
1285
|
+
...base(),
|
|
1286
|
+
type: "x-agent-native.persisted-event-omission",
|
|
1287
|
+
payload: { sourceType: event.type },
|
|
1288
|
+
});
|
|
1289
|
+
lastOmissionByRun.set(event.runId, {
|
|
1290
|
+
index,
|
|
1291
|
+
firstSequence: event.sequence,
|
|
1292
|
+
lastSequence: event.sequence,
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
return persisted;
|
|
1209
1296
|
}
|
|
1210
1297
|
function persistedMessages(messages) {
|
|
1211
1298
|
return messages.map((message) => ({
|
|
@@ -1807,14 +1894,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1807
1894
|
const updatedAt = timestamp(stored.updatedAt, createdAt);
|
|
1808
1895
|
const repository = storedRepository(stored);
|
|
1809
1896
|
const agentKit = asRecord(repository.agentKit);
|
|
1810
|
-
const failedRunIds =
|
|
1811
|
-
const run = asRecord(value);
|
|
1812
|
-
return run?.status === "failed" &&
|
|
1813
|
-
asRecord(run.error) &&
|
|
1814
|
-
typeof run.id === "string"
|
|
1815
|
-
? [run.id]
|
|
1816
|
-
: [];
|
|
1817
|
-
}));
|
|
1897
|
+
const failedRunIds = failedRunIdsWithError(agentKit?.runs);
|
|
1818
1898
|
const storedMessageProjection = storedMessages(repository.messages, now, options.adapter?.textFormat).filter((message) => !isRenderedRunNotStartedNotice(message, failedRunIds));
|
|
1819
1899
|
const queuedMessages = storedQueue(repository.queuedMessages, threadId, updatedAt);
|
|
1820
1900
|
const agentKitMessages = Array.isArray(agentKit?.messages)
|
|
@@ -2184,7 +2264,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
2184
2264
|
.filter((run) => ["awaiting_approval", "awaiting_input"].includes(run.status))
|
|
2185
2265
|
.map((run) => run.id)
|
|
2186
2266
|
: [];
|
|
2187
|
-
const failedRunIds =
|
|
2267
|
+
const failedRunIds = failedRunIdsWithError(runs);
|
|
2188
2268
|
const messages = reconcileDurableMessages(thread.messages, durableMessages.filter((message) => !isRenderedRunNotStartedNotice(message, failedRunIds)), thread.events, runs, thread.toolCalls);
|
|
2189
2269
|
const replayFromStart = [
|
|
2190
2270
|
"running",
|
|
@@ -2339,17 +2419,11 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
2339
2419
|
}
|
|
2340
2420
|
const changedEvents = compactEvents.filter((event) => changedEventRunIds.has(event.runId));
|
|
2341
2421
|
const eventRunLastSequenceById = new Map();
|
|
2342
|
-
for (const run of input.snapshot.runs ?? []) {
|
|
2343
|
-
if (typeof run.id === "string" &&
|
|
2344
|
-
Number.isSafeInteger(run.lastSequence) &&
|
|
2345
|
-
run.lastSequence >= 0) {
|
|
2346
|
-
eventRunLastSequenceById.set(run.id, run.lastSequence);
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
2422
|
for (const event of input.snapshot.events ?? []) {
|
|
2350
2423
|
const previousSequence = eventRunLastSequenceById.get(event.runId) ?? 0;
|
|
2351
|
-
|
|
2352
|
-
|
|
2424
|
+
const sequenceEnd = agentEventSequenceEnd(event);
|
|
2425
|
+
if (Number.isSafeInteger(sequenceEnd)) {
|
|
2426
|
+
eventRunLastSequenceById.set(event.runId, Math.max(previousSequence, sequenceEnd));
|
|
2353
2427
|
}
|
|
2354
2428
|
}
|
|
2355
2429
|
const changedEventsByRun = new Map();
|
|
@@ -770,6 +770,53 @@ function isSyntheticToolHistoryOmissionMessage(message) {
|
|
|
770
770
|
(message.id === AGENTKIT_TOOL_HISTORY_OMISSION_MESSAGE_ID_PREFIX ||
|
|
771
771
|
/^agentkit-tool-history-omission-\d+$/.test(message.id)));
|
|
772
772
|
}
|
|
773
|
+
function equivalentRuntimeContent(left, right) {
|
|
774
|
+
let remaining = 4096;
|
|
775
|
+
const leftAncestors = new WeakSet();
|
|
776
|
+
const rightAncestors = new WeakSet();
|
|
777
|
+
const compare = (a, b, depth) => {
|
|
778
|
+
if (--remaining < 0 || depth > 64)
|
|
779
|
+
return false;
|
|
780
|
+
if (Object.is(a, b))
|
|
781
|
+
return true;
|
|
782
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object")
|
|
783
|
+
return false;
|
|
784
|
+
const prototype = Object.getPrototypeOf(a);
|
|
785
|
+
if (prototype !== Object.getPrototypeOf(b) ||
|
|
786
|
+
(prototype !== Object.prototype &&
|
|
787
|
+
prototype !== Array.prototype &&
|
|
788
|
+
prototype !== null) ||
|
|
789
|
+
leftAncestors.has(a) ||
|
|
790
|
+
rightAncestors.has(b))
|
|
791
|
+
return false;
|
|
792
|
+
if (Array.isArray(a) !== Array.isArray(b))
|
|
793
|
+
return false;
|
|
794
|
+
if (Array.isArray(a) && (!Array.isArray(b) || a.length !== b.length))
|
|
795
|
+
return false;
|
|
796
|
+
const keys = Object.keys(a);
|
|
797
|
+
if (keys.length > remaining || keys.length !== Object.keys(b).length)
|
|
798
|
+
return false;
|
|
799
|
+
leftAncestors.add(a);
|
|
800
|
+
rightAncestors.add(b);
|
|
801
|
+
try {
|
|
802
|
+
return keys.every((key) => {
|
|
803
|
+
const leftValue = Object.getOwnPropertyDescriptor(a, key);
|
|
804
|
+
const rightValue = Object.getOwnPropertyDescriptor(b, key);
|
|
805
|
+
return Boolean(leftValue &&
|
|
806
|
+
rightValue &&
|
|
807
|
+
rightValue.enumerable &&
|
|
808
|
+
"value" in leftValue &&
|
|
809
|
+
"value" in rightValue &&
|
|
810
|
+
compare(leftValue.value, rightValue.value, depth + 1));
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
finally {
|
|
814
|
+
leftAncestors.delete(a);
|
|
815
|
+
rightAncestors.delete(b);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
return compare(left, right, 0);
|
|
819
|
+
}
|
|
773
820
|
function priorNativeHistoryMessages(messages, currentPrompt) {
|
|
774
821
|
const source = messages ?? [];
|
|
775
822
|
let currentPromptMessageIndex;
|
|
@@ -2864,6 +2911,18 @@ export function createAgentNativeChatRuntime(options = {}) {
|
|
|
2864
2911
|
const latestUserMessage = [...(turn.messages ?? [])]
|
|
2865
2912
|
.reverse()
|
|
2866
2913
|
.find((message) => message.role === "user");
|
|
2914
|
+
const latestUserMessageIndex = latestUserMessage
|
|
2915
|
+
? (turn.messages?.lastIndexOf(latestUserMessage) ?? -1)
|
|
2916
|
+
: -1;
|
|
2917
|
+
const messagesForHistory = latestUserMessage &&
|
|
2918
|
+
typeof latestUserMessage.id === "string" &&
|
|
2919
|
+
latestUserMessage.id.trim().length > 0 &&
|
|
2920
|
+
latestUserMessageIndex >= 0
|
|
2921
|
+
? turn.messages.filter((message, index) => message.role !== "user" ||
|
|
2922
|
+
message.id !== latestUserMessage.id ||
|
|
2923
|
+
!equivalentRuntimeContent(message.content, latestUserMessage.content) ||
|
|
2924
|
+
index === latestUserMessageIndex)
|
|
2925
|
+
: turn.messages;
|
|
2867
2926
|
const prompt = turn.prompt ??
|
|
2868
2927
|
latestUserMessage?.content
|
|
2869
2928
|
.map((part) => (part.type === "text" ? part.text : ""))
|
|
@@ -2884,12 +2943,12 @@ export function createAgentNativeChatRuntime(options = {}) {
|
|
|
2884
2943
|
? turnEngine
|
|
2885
2944
|
: options.engine;
|
|
2886
2945
|
const currentAttachmentUrlSet = currentTurnAttachmentUrls(turn.attachments);
|
|
2887
|
-
const history = nativeHistoryFromMessages(
|
|
2946
|
+
const history = nativeHistoryFromMessages(messagesForHistory, prompt, currentAttachmentUrlSet);
|
|
2888
2947
|
const loadedSkillSlugs = loadedSkillSlugsFromMessages(turn.messages);
|
|
2889
2948
|
const pendingApprovalHistory = approvedToolCalls && continuationMessageState
|
|
2890
2949
|
? pendingApprovalRuntimeMessages(continuationMessageState)
|
|
2891
2950
|
: { messages: [], omitted: false, toolHistoryOmitted: false };
|
|
2892
|
-
const structuredHistory = nativeStructuredHistoryFromMessages(
|
|
2951
|
+
const structuredHistory = nativeStructuredHistoryFromMessages(messagesForHistory, prompt, currentAttachmentUrlSet, pendingApprovalHistory.messages, pendingApprovalHistory.omitted, pendingApprovalHistory.toolHistoryOmitted);
|
|
2893
2952
|
return {
|
|
2894
2953
|
message: prompt,
|
|
2895
2954
|
...(latestUserMessage?.id
|
|
@@ -55,10 +55,6 @@ async function requestFirstRunOnboardingStatus() {
|
|
|
55
55
|
dispatchFirstRunOnboardingStatus(firstRun);
|
|
56
56
|
return firstRun;
|
|
57
57
|
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
dispatchFirstRunOnboardingStatus(false);
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
62
58
|
finally {
|
|
63
59
|
if (timeoutId !== undefined)
|
|
64
60
|
clearTimeout(timeoutId);
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
13
13
|
};
|
|
14
14
|
}>>;
|
|
15
15
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -11,9 +11,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
11
11
|
enabled?: undefined;
|
|
12
12
|
nextRun?: undefined;
|
|
13
13
|
} | {
|
|
14
|
-
deleted?: undefined;
|
|
15
14
|
name: string;
|
|
16
15
|
enabled: boolean;
|
|
17
16
|
nextRun: string;
|
|
17
|
+
deleted?: undefined;
|
|
18
18
|
}>;
|
|
19
19
|
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function connectionApp(origin: string, appId?: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* The connect CLI sends the clients it sets up as comma-joined client ids.
|
|
4
|
+
* Any other device client value, such as "Example, Inc.", is one name.
|
|
5
|
+
*/
|
|
6
|
+
export declare function deviceFlowClients(client: string | null): string | string[] | null;
|
|
7
|
+
export declare function trackAgentConnected(input: {
|
|
8
|
+
email: string;
|
|
9
|
+
origin: string;
|
|
10
|
+
appId?: string;
|
|
11
|
+
client: string | readonly string[] | null;
|
|
12
|
+
method: "mcp" | "oauth";
|
|
13
|
+
}): Promise<"emitted" | "duplicate" | "disabled" | "failed">;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { CLIENTS } from "../cli/mcp-config-writers.js";
|
|
3
|
+
import { mutateSetting } from "../settings/store.js";
|
|
4
|
+
import { normalizeTrackingDimension } from "../shared/analytics-events.js";
|
|
5
|
+
import { resolveMcpConnectHostId } from "../shared/mcp-connect-content.js";
|
|
6
|
+
import { isTrackingSuppressed, listTrackingProviders, track, } from "../tracking/registry.js";
|
|
7
|
+
import { detectVendorClient } from "./analytics.js";
|
|
8
|
+
import { connectAppLabel, connectEnvironment } from "./connect-app-label.js";
|
|
9
|
+
export function connectionApp(origin, appId) {
|
|
10
|
+
return normalizeTrackingDimension(connectAppLabel(origin, { appId }, connectEnvironment()));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The connect CLI sends the clients it sets up as comma-joined client ids.
|
|
14
|
+
* Any other device client value, such as "Example, Inc.", is one name.
|
|
15
|
+
*/
|
|
16
|
+
export function deviceFlowClients(client) {
|
|
17
|
+
const ids = client?.split(",");
|
|
18
|
+
return ids?.every((id) => CLIENTS.includes(id)) ? ids : client;
|
|
19
|
+
}
|
|
20
|
+
export async function trackAgentConnected(input) {
|
|
21
|
+
// Everything runs inside the try: the connection is already committed, so a
|
|
22
|
+
// tracking or configuration failure must not turn it into a failed response.
|
|
23
|
+
try {
|
|
24
|
+
if (listTrackingProviders().length === 0 ||
|
|
25
|
+
isTrackingSuppressed(input.email))
|
|
26
|
+
return "disabled";
|
|
27
|
+
const app = connectionApp(input.origin, input.appId);
|
|
28
|
+
const raw = input.client;
|
|
29
|
+
const clients = new Set((typeof raw === "string" ? [raw] : (raw ?? ["unknown"])).map((name) => resolveMcpConnectHostId(name) ??
|
|
30
|
+
detectVendorClient(name) ??
|
|
31
|
+
(name.trim().toLowerCase().slice(0, 120) || "unknown")));
|
|
32
|
+
let emitted = false;
|
|
33
|
+
for (const client of clients) {
|
|
34
|
+
const email = input.email.trim().toLowerCase();
|
|
35
|
+
const key = createHash("sha256")
|
|
36
|
+
.update(JSON.stringify([email, app, client]))
|
|
37
|
+
.digest("hex");
|
|
38
|
+
const claimId = randomUUID();
|
|
39
|
+
// Both success paths share a durable CAS claim; process-local state
|
|
40
|
+
// cannot suppress reconnects across serverless invocations.
|
|
41
|
+
const claim = await mutateSetting(`agent-connected:${key}`, (current) => {
|
|
42
|
+
if (current && typeof current.claim_id !== "string") {
|
|
43
|
+
throw new Error("Invalid agent connection claim");
|
|
44
|
+
}
|
|
45
|
+
return current ?? { claim_id: claimId };
|
|
46
|
+
});
|
|
47
|
+
if (claim.claim_id !== claimId)
|
|
48
|
+
continue;
|
|
49
|
+
track("agent_connected", {
|
|
50
|
+
email,
|
|
51
|
+
app,
|
|
52
|
+
client,
|
|
53
|
+
connection_method: input.method,
|
|
54
|
+
}, { userId: email });
|
|
55
|
+
emitted = true;
|
|
56
|
+
}
|
|
57
|
+
return emitted ? "emitted" : "duplicate";
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error("[agent-connected] Failed to record connection:", error);
|
|
61
|
+
return "failed";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { McpConnectEnvironment } from "../shared/mcp-connect-content.js";
|
|
2
|
+
export declare function connectEnvironment(): McpConnectEnvironment;
|
|
3
|
+
/**
|
|
4
|
+
* The app a connection belongs to. The connect identity names its MCP server
|
|
5
|
+
* from this and the `agent_connected` event reports it, so the two cannot
|
|
6
|
+
* disagree about which app a client connected to.
|
|
7
|
+
*/
|
|
8
|
+
export declare function connectAppLabel(origin: string, options: {
|
|
9
|
+
appId?: string;
|
|
10
|
+
appName?: string;
|
|
11
|
+
}, environment: McpConnectEnvironment): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
2
|
+
import { isAgentNativeDeploymentEnvironment } from "../config.js";
|
|
3
|
+
import { resolveDeployEnvironment } from "../server/deploy-environment.js";
|
|
4
|
+
export function connectEnvironment() {
|
|
5
|
+
const environment = resolveDeployEnvironment();
|
|
6
|
+
if (!isAgentNativeDeploymentEnvironment(environment)) {
|
|
7
|
+
throw new Error(`Unknown deployment environment "${environment}"`);
|
|
8
|
+
}
|
|
9
|
+
return environment;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The app a connection belongs to. The connect identity names its MCP server
|
|
13
|
+
* from this and the `agent_connected` event reports it, so the two cannot
|
|
14
|
+
* disagree about which app a client connected to.
|
|
15
|
+
*/
|
|
16
|
+
export function connectAppLabel(origin, options, environment) {
|
|
17
|
+
const app = getAppConfig().app;
|
|
18
|
+
const declared = options.appId ?? app.id ?? app.template ?? app.slug;
|
|
19
|
+
if (declared)
|
|
20
|
+
return declared;
|
|
21
|
+
// Deployed functions run without npm's `npm_package_name`, so first-party
|
|
22
|
+
// apps usually land here. A beta lane is `beta.<app>.agent-native.com`: its
|
|
23
|
+
// leading label names the lane, and every beta app would share it. Only a
|
|
24
|
+
// beta deployment drops it, so no production name changes.
|
|
25
|
+
try {
|
|
26
|
+
const host = new URL(origin).hostname;
|
|
27
|
+
const h = environment === "beta" ? host.replace(/^beta\./, "") : host;
|
|
28
|
+
return h.split(".")[0] || h;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return options.appName || "app";
|
|
32
|
+
}
|
|
33
|
+
}
|