@agent-native/core 0.200.0 → 0.200.1-nightly-20261002183718
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/engine/ai-sdk-engine.js +8 -1
- package/dist/agent/engine/translate-ai-sdk.d.ts +1 -1
- package/dist/agent/engine/translate-ai-sdk.js +2 -1
- package/dist/agent/run-manager.d.ts +7 -0
- package/dist/agent/run-manager.js +4 -0
- package/dist/agent/thread-data-builder.js +63 -14
- package/dist/client/chat/agentkit-agent-native.js +26 -14
- package/dist/client/use-chat-threads.js +48 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat-plugin.js +6 -2
- 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/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +3 -3
- package/package.json +3 -3
|
@@ -279,8 +279,15 @@ class AISDKEngine {
|
|
|
279
279
|
}
|
|
280
280
|
const toolNameMap = createProviderToolNameMap(opts.tools, opts.messages);
|
|
281
281
|
const providerTools = limitProviderTools(opts.tools);
|
|
282
|
+
// The Responses API treats an omitted `strict` as strict mode and rewrites
|
|
283
|
+
// every optional parameter as required, so the model must invent a value
|
|
284
|
+
// ("" or a guessed id) for each one. Action schemas use omission to mean
|
|
285
|
+
// "not this mode", so those fillers turn a valid call into a mixed one
|
|
286
|
+
// that validation rejects on every retry.
|
|
287
|
+
const usesResponsesApi = this.provider === "openai" &&
|
|
288
|
+
(this.forceResponses || !isCustomOpenAiBaseUrl(this.baseUrl));
|
|
282
289
|
const aiSdkTools = providerTools.length > 0
|
|
283
|
-
? engineToolsToAISDK(providerTools, jsonSchema, toolNameMap)
|
|
290
|
+
? engineToolsToAISDK(providerTools, jsonSchema, toolNameMap, usesResponsesApi ? false : undefined)
|
|
284
291
|
: undefined;
|
|
285
292
|
const messages = engineMessagesToAISDK(opts.messages, {
|
|
286
293
|
toolResultImages: this.capabilities.vision,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ProviderToolNameMap } from "./tool-name.js";
|
|
2
2
|
import type { EngineTool, EngineMessage, EngineContentPart, EngineEvent } from "./types.js";
|
|
3
|
-
export declare function engineToolsToAISDK(tools: EngineTool[], jsonSchema?: (schema: Record<string, unknown>) => unknown, toolNameMap?: ProviderToolNameMap): Record<string, any>;
|
|
3
|
+
export declare function engineToolsToAISDK(tools: EngineTool[], jsonSchema?: (schema: Record<string, unknown>) => unknown, toolNameMap?: ProviderToolNameMap, strict?: boolean): Record<string, any>;
|
|
4
4
|
export interface EngineToAISDKOptions {
|
|
5
5
|
toolResultImages?: boolean;
|
|
6
6
|
toolNameMap?: ProviderToolNameMap;
|
|
@@ -2,7 +2,7 @@ import { classifyProviderError, describeErrorWithCauses, } from "./error-detail.
|
|
|
2
2
|
import { flattenComposedRootSchema } from "./flatten-composed-root-schema.js";
|
|
3
3
|
import { createProviderToolNameMap, toEngineToolName, toProviderToolName, } from "./tool-name.js";
|
|
4
4
|
import { backfillEngineMessagesToolResults } from "./translate-anthropic.js";
|
|
5
|
-
export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProviderToolNameMap(tools)) {
|
|
5
|
+
export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProviderToolNameMap(tools), strict) {
|
|
6
6
|
const result = {};
|
|
7
7
|
for (const tool of tools) {
|
|
8
8
|
const inputSchema = flattenComposedRootSchema(tool.inputSchema);
|
|
@@ -16,6 +16,7 @@ export function engineToolsToAISDK(tools, jsonSchema, toolNameMap = createProvid
|
|
|
16
16
|
result[providerName] = {
|
|
17
17
|
description: tool.description,
|
|
18
18
|
inputSchema: jsonSchema ? jsonSchema(rawSchema) : rawSchema,
|
|
19
|
+
...(strict === undefined ? {} : { strict }),
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
return result;
|
|
@@ -112,6 +112,13 @@ export declare function getActiveRunForThreadAsync(threadId: string): Promise<{
|
|
|
112
112
|
threadId: string;
|
|
113
113
|
turnId: string;
|
|
114
114
|
status: string;
|
|
115
|
+
/**
|
|
116
|
+
* The one answer to "is a run in flight on this thread". A terminal run is
|
|
117
|
+
* still returned inside `TERMINAL_RUN_RECONNECT_WINDOW_MS` so a reconnecting
|
|
118
|
+
* client can replay it, which is why `status` alone being present means
|
|
119
|
+
* nothing; `/runs/active` reports this as its `active` flag.
|
|
120
|
+
*/
|
|
121
|
+
inFlight: boolean;
|
|
115
122
|
heartbeatAt: number;
|
|
116
123
|
lastProgressAt: number | null;
|
|
117
124
|
dispatchMode?: string | null;
|
|
@@ -1811,6 +1811,7 @@ export async function getActiveRunForThreadAsync(threadId) {
|
|
|
1811
1811
|
threadId: successor.threadId,
|
|
1812
1812
|
turnId: successor.turnId ?? successor.id,
|
|
1813
1813
|
status: successor.status,
|
|
1814
|
+
inFlight: true,
|
|
1814
1815
|
heartbeatAt: successor.heartbeatAt ?? successor.startedAt,
|
|
1815
1816
|
lastProgressAt: successor.lastProgressAt,
|
|
1816
1817
|
dispatchMode: successor.dispatchMode,
|
|
@@ -1833,6 +1834,7 @@ export async function getActiveRunForThreadAsync(threadId) {
|
|
|
1833
1834
|
threadId: memRun.threadId,
|
|
1834
1835
|
turnId: memRun.turnId,
|
|
1835
1836
|
status,
|
|
1837
|
+
inFlight: status === "running",
|
|
1836
1838
|
heartbeatAt,
|
|
1837
1839
|
lastProgressAt: sqlSnapshot?.lastProgressAt ?? null,
|
|
1838
1840
|
dispatchMode: sqlSnapshot?.dispatchMode ?? null,
|
|
@@ -1896,6 +1898,7 @@ export async function getActiveRunForThreadAsync(threadId) {
|
|
|
1896
1898
|
threadId: sqlRun.threadId,
|
|
1897
1899
|
turnId: sqlRun.turnId ?? sqlRun.id,
|
|
1898
1900
|
status: sqlRun.status,
|
|
1901
|
+
inFlight: true,
|
|
1899
1902
|
heartbeatAt: sqlRun.heartbeatAt ?? sqlRun.startedAt,
|
|
1900
1903
|
lastProgressAt: sqlRun.lastProgressAt,
|
|
1901
1904
|
dispatchMode: sqlRun.dispatchMode,
|
|
@@ -1917,6 +1920,7 @@ export async function getActiveRunForThreadAsync(threadId) {
|
|
|
1917
1920
|
threadId: sqlRun.threadId,
|
|
1918
1921
|
turnId: sqlRun.turnId ?? sqlRun.id,
|
|
1919
1922
|
status: legacyWireRunStatus(sqlRun.status),
|
|
1923
|
+
inFlight: false,
|
|
1920
1924
|
heartbeatAt: sqlRun.heartbeatAt ?? sqlRun.startedAt,
|
|
1921
1925
|
lastProgressAt: sqlRun.lastProgressAt,
|
|
1922
1926
|
dispatchMode: sqlRun.dispatchMode,
|
|
@@ -423,12 +423,15 @@ function normalizeContentForFingerprint(content) {
|
|
|
423
423
|
? { ...part, toolCallId: undefined }
|
|
424
424
|
: part);
|
|
425
425
|
}
|
|
426
|
-
function messageIdentityKeySet(message) {
|
|
426
|
+
function messageIdentityKeySet(message, eventRunIds) {
|
|
427
427
|
const strong = [];
|
|
428
428
|
if (typeof message?.id === "string" && message.id) {
|
|
429
429
|
strong.push(`id:${message.id}`);
|
|
430
430
|
}
|
|
431
|
-
const runId = getMessageRunId(message)
|
|
431
|
+
const runId = getMessageRunId(message) ??
|
|
432
|
+
(typeof message?.id === "string"
|
|
433
|
+
? eventRunIds?.get(message.id)
|
|
434
|
+
: undefined);
|
|
432
435
|
if (runId)
|
|
433
436
|
strong.push(`run:${runId}`);
|
|
434
437
|
const turnId = turnIdOf(message);
|
|
@@ -1425,9 +1428,7 @@ export function mergeThreadDataForClientSave(existingRepo, incomingRepo, options
|
|
|
1425
1428
|
existingNormalized &&
|
|
1426
1429
|
typeof existingNormalized === "object") {
|
|
1427
1430
|
for (const [key, value] of Object.entries(existingNormalized)) {
|
|
1428
|
-
if (key === "messages" || key === "headId")
|
|
1429
|
-
continue;
|
|
1430
|
-
if (key === "queuedMessages" && !preserveExistingQueuedMessages) {
|
|
1431
|
+
if (key === "messages" || key === "headId" || key === "queuedMessages") {
|
|
1431
1432
|
continue;
|
|
1432
1433
|
}
|
|
1433
1434
|
if (!(key in merged)) {
|
|
@@ -1435,11 +1436,11 @@ export function mergeThreadDataForClientSave(existingRepo, incomingRepo, options
|
|
|
1435
1436
|
}
|
|
1436
1437
|
}
|
|
1437
1438
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1439
|
+
// Queue mutations are the only writer of the queue and opt out here. Any
|
|
1440
|
+
// other save carries a queue it read earlier, and letting that copy win drops
|
|
1441
|
+
// a promotion claim or an append that landed in between.
|
|
1442
|
+
if (preserveExistingQueuedMessages &&
|
|
1443
|
+
existingNormalized?.queuedMessages !== undefined) {
|
|
1443
1444
|
merged.queuedMessages = existingNormalized.queuedMessages;
|
|
1444
1445
|
}
|
|
1445
1446
|
if (merged.agentKit !== undefined) {
|
|
@@ -1454,10 +1455,30 @@ export function mergeThreadDataForClientSave(existingRepo, incomingRepo, options
|
|
|
1454
1455
|
if (!existingMessages || !incomingMessages) {
|
|
1455
1456
|
return pruneClaimedQueuedMessages(merged);
|
|
1456
1457
|
}
|
|
1457
|
-
|
|
1458
|
+
// The chat UI saves its replies under AgentKit ids with no runId; only the
|
|
1459
|
+
// AgentKit events tie them to the run the server folded under its own id.
|
|
1460
|
+
const eventRunIds = snapshotMessageRunIds(merged.agentKit);
|
|
1461
|
+
const incomingKeySets = incomingMessages.map((entry) => messageIdentityKeySet(getStoredMessage(entry), eventRunIds));
|
|
1458
1462
|
const usedIncoming = new Set();
|
|
1459
1463
|
const nextMessages = [];
|
|
1460
1464
|
const idRewrites = new Map();
|
|
1465
|
+
// A message that keeps its own id owns the incoming copy with that id; a
|
|
1466
|
+
// run or turn match is weaker and must not take it from the message itself.
|
|
1467
|
+
const incomingByOwnId = new Map();
|
|
1468
|
+
existingMessages.forEach((entry, existingIndex) => {
|
|
1469
|
+
const existingMessage = getStoredMessage(entry);
|
|
1470
|
+
const id = messageId(existingMessage);
|
|
1471
|
+
if (!id ||
|
|
1472
|
+
(existingMessage?.role === "assistant" &&
|
|
1473
|
+
messageContentIsEmpty(existingMessage.content))) {
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
const incomingIndex = incomingKeySets.findIndex((keys, index) => !usedIncoming.has(index) && keys.strong.includes(`id:${id}`));
|
|
1477
|
+
if (incomingIndex === -1)
|
|
1478
|
+
return;
|
|
1479
|
+
usedIncoming.add(incomingIndex);
|
|
1480
|
+
incomingByOwnId.set(existingIndex, incomingIndex);
|
|
1481
|
+
});
|
|
1461
1482
|
for (let existingIndex = 0; existingIndex < existingMessages.length; existingIndex++) {
|
|
1462
1483
|
const existingEntry = existingMessages[existingIndex];
|
|
1463
1484
|
const existingMessage = getStoredMessage(existingEntry);
|
|
@@ -1465,8 +1486,9 @@ export function mergeThreadDataForClientSave(existingRepo, incomingRepo, options
|
|
|
1465
1486
|
messageContentIsEmpty(existingMessage.content)) {
|
|
1466
1487
|
continue;
|
|
1467
1488
|
}
|
|
1468
|
-
const existingKeys = messageIdentityKeySet(existingMessage);
|
|
1469
|
-
const incomingIndex =
|
|
1489
|
+
const existingKeys = messageIdentityKeySet(existingMessage, eventRunIds);
|
|
1490
|
+
const incomingIndex = incomingByOwnId.get(existingIndex) ??
|
|
1491
|
+
findRankedIdentityMatch(existingKeys, incomingKeySets, usedIncoming, existingIndex);
|
|
1470
1492
|
if (incomingIndex === -1) {
|
|
1471
1493
|
nextMessages.push(existingEntry);
|
|
1472
1494
|
continue;
|
|
@@ -1491,7 +1513,34 @@ export function mergeThreadDataForClientSave(existingRepo, incomingRepo, options
|
|
|
1491
1513
|
}
|
|
1492
1514
|
nextMessages.push(incomingMessages[index]);
|
|
1493
1515
|
}
|
|
1494
|
-
|
|
1516
|
+
// One reply per run: the server's folded reply carries the run in its
|
|
1517
|
+
// metadata, and the chat UI's own copy of it (saved under an AgentKit id,
|
|
1518
|
+
// tied to the run only by events) is dropped wherever both ended up stored.
|
|
1519
|
+
const serverReplyRuns = new Set();
|
|
1520
|
+
for (const entry of nextMessages) {
|
|
1521
|
+
const message = getStoredMessage(entry);
|
|
1522
|
+
const runId = message?.role === "assistant" ? getMessageRunId(message) : null;
|
|
1523
|
+
if (runId)
|
|
1524
|
+
serverReplyRuns.add(runId);
|
|
1525
|
+
}
|
|
1526
|
+
const keptMessages = nextMessages.filter((entry) => {
|
|
1527
|
+
const message = getStoredMessage(entry);
|
|
1528
|
+
if (message?.role !== "assistant" || getMessageRunId(message))
|
|
1529
|
+
return true;
|
|
1530
|
+
const runId = typeof message.id === "string" ? eventRunIds.get(message.id) : undefined;
|
|
1531
|
+
if (!runId || !serverReplyRuns.has(runId))
|
|
1532
|
+
return true;
|
|
1533
|
+
const kept = nextMessages.find((candidate) => {
|
|
1534
|
+
const other = getStoredMessage(candidate);
|
|
1535
|
+
return other?.role === "assistant" && getMessageRunId(other) === runId;
|
|
1536
|
+
});
|
|
1537
|
+
const keptId = messageId(getStoredMessage(kept));
|
|
1538
|
+
const droppedId = messageId(message);
|
|
1539
|
+
if (keptId && droppedId)
|
|
1540
|
+
idRewrites.set(droppedId, keptId);
|
|
1541
|
+
return false;
|
|
1542
|
+
});
|
|
1543
|
+
merged.messages = keptMessages.map((entry) => rewriteEntryParentId(entry, idRewrites));
|
|
1495
1544
|
const normalizedMerged = normalizeThreadRepository(pruneClaimedQueuedMessages(merged));
|
|
1496
1545
|
normalizedMerged.headId = chooseMergedHeadId(existingNormalized, incomingNormalized, normalizedMerged);
|
|
1497
1546
|
const previousUser = latestStoredUser(existingNormalized);
|
|
@@ -1324,10 +1324,13 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1324
1324
|
async function activeRunSnapshot(threadId) {
|
|
1325
1325
|
const value = await activeRunStatus(threadId);
|
|
1326
1326
|
const status = value.status;
|
|
1327
|
-
if (value.active
|
|
1328
|
-
return null;
|
|
1329
|
-
if (value.active !== true)
|
|
1327
|
+
if (typeof value.active !== "boolean")
|
|
1330
1328
|
return undefined;
|
|
1329
|
+
// An idle thread has no run; a run that just finished keeps its id and
|
|
1330
|
+
// status for replay even though it is no longer `active`.
|
|
1331
|
+
if (value.active === false && (status === "idle" || !value.runId)) {
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1331
1334
|
if (typeof value.runId !== "string" || !value.runId) {
|
|
1332
1335
|
throw new TypeError("Agent chat active-run response must include an active run ID.");
|
|
1333
1336
|
}
|
|
@@ -1651,15 +1654,21 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1651
1654
|
...(claimedMessage ? { claimedMessage } : {}),
|
|
1652
1655
|
};
|
|
1653
1656
|
}
|
|
1657
|
+
// A server that predates `active` meaning "in flight" reports a run inside
|
|
1658
|
+
// its reconnect window as `active` with a terminal status.
|
|
1659
|
+
function runIsInFlight(status) {
|
|
1660
|
+
return (status.active === true &&
|
|
1661
|
+
![
|
|
1662
|
+
"completed",
|
|
1663
|
+
"complete",
|
|
1664
|
+
"failed",
|
|
1665
|
+
"cancelled",
|
|
1666
|
+
"errored",
|
|
1667
|
+
"aborted",
|
|
1668
|
+
].includes(String(status.status ?? "")));
|
|
1669
|
+
}
|
|
1654
1670
|
function runSlotIsClear(status) {
|
|
1655
|
-
return
|
|
1656
|
-
(status.active !== true ||
|
|
1657
|
-
status.status === "completed" ||
|
|
1658
|
-
status.status === "complete" ||
|
|
1659
|
-
status.status === "failed" ||
|
|
1660
|
-
status.status === "cancelled" ||
|
|
1661
|
-
status.status === "errored" ||
|
|
1662
|
-
status.status === "aborted"));
|
|
1671
|
+
return status.awaitingRedispatch !== true && !runIsInFlight(status);
|
|
1663
1672
|
}
|
|
1664
1673
|
async function waitForRunSlot(threadId, maxPolls = RUN_SLOT_STABLE_POLLS * 2) {
|
|
1665
1674
|
let consecutiveClearPolls = 0;
|
|
@@ -1838,11 +1847,14 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1838
1847
|
throw new TypeError("Agent chat queue claim response is invalid.");
|
|
1839
1848
|
}
|
|
1840
1849
|
if (interruptActiveRun) {
|
|
1841
|
-
const activeRun = await
|
|
1842
|
-
if (activeRun) {
|
|
1850
|
+
const activeRun = await activeRunStatus(threadId);
|
|
1851
|
+
if (runIsInFlight(activeRun)) {
|
|
1852
|
+
if (typeof activeRun.runId !== "string" || !activeRun.runId) {
|
|
1853
|
+
throw new TypeError("Agent chat active-run response must include an active run ID.");
|
|
1854
|
+
}
|
|
1843
1855
|
await transport.cancelRun({
|
|
1844
1856
|
threadId,
|
|
1845
|
-
runId: activeRun.
|
|
1857
|
+
runId: activeRun.runId,
|
|
1846
1858
|
});
|
|
1847
1859
|
await waitForRunSlot(threadId, RUN_SLOT_STABLE_POLLS * 4);
|
|
1848
1860
|
}
|
|
@@ -81,6 +81,26 @@ export function appendChatThreadScopeParams(params, scope) {
|
|
|
81
81
|
params.set("scopeType", scope.type);
|
|
82
82
|
params.set("scopeId", scope.id);
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* The scope a thread save reports for the thread: a scope, `null` when the
|
|
86
|
+
* server holds the thread unscoped, `undefined` when the response says nothing
|
|
87
|
+
* (an older server or an unreadable body), so the local scope is left alone.
|
|
88
|
+
*/
|
|
89
|
+
function savedThreadScope(body) {
|
|
90
|
+
const record = body;
|
|
91
|
+
if (!record || typeof record !== "object" || !("scope" in record)) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
const scope = record.scope;
|
|
95
|
+
if (scope === null)
|
|
96
|
+
return null;
|
|
97
|
+
if (!scope || typeof scope !== "object")
|
|
98
|
+
return undefined;
|
|
99
|
+
const { type, id } = scope;
|
|
100
|
+
return typeof type === "string" && typeof id === "string"
|
|
101
|
+
? scope
|
|
102
|
+
: undefined;
|
|
103
|
+
}
|
|
84
104
|
function withChatThreadScope(url, scope) {
|
|
85
105
|
const params = new URLSearchParams();
|
|
86
106
|
appendChatThreadScopeParams(params, scope);
|
|
@@ -239,6 +259,9 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
239
259
|
? new Set([initialActiveThreadRef.current.id])
|
|
240
260
|
: new Set());
|
|
241
261
|
const explicitlyOpenedThreadIdsRef = useRef(new Set());
|
|
262
|
+
// Bumped when a thread's scope is changed on purpose (detach), so a save
|
|
263
|
+
// response that was in flight across the change cannot restore the old scope.
|
|
264
|
+
const scopeMutationsRef = useRef(new Map());
|
|
242
265
|
const optimisticThreadScopesRef = useRef(new Map());
|
|
243
266
|
const knownThreadScopesRef = useRef(new Map());
|
|
244
267
|
const serverConfirmedThreadIdsRef = useRef(new Set());
|
|
@@ -728,6 +751,8 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
728
751
|
routeThreadId,
|
|
729
752
|
]);
|
|
730
753
|
const detachThread = useCallback(async (threadId) => {
|
|
754
|
+
const bumpScopeMutation = () => scopeMutationsRef.current.set(threadId, (scopeMutationsRef.current.get(threadId) ?? 0) + 1);
|
|
755
|
+
bumpScopeMutation();
|
|
731
756
|
try {
|
|
732
757
|
const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}`, historyScope), {
|
|
733
758
|
method: "PUT",
|
|
@@ -738,6 +763,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
738
763
|
await fetchThreads();
|
|
739
764
|
return;
|
|
740
765
|
}
|
|
766
|
+
bumpScopeMutation();
|
|
741
767
|
knownThreadScopesRef.current.set(threadId, null);
|
|
742
768
|
optimisticThreadScopesRef.current.set(threadId, null);
|
|
743
769
|
const wasActive = activeThreadIdRef.current === threadId;
|
|
@@ -969,6 +995,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
969
995
|
// rides only on creation: a periodic save must never move an existing thread
|
|
970
996
|
// between resources, however stale this client's guess is.
|
|
971
997
|
const saveThreadData = useCallback(async (id, data) => {
|
|
998
|
+
const scopeEpoch = scopeMutationsRef.current.get(id) ?? 0;
|
|
972
999
|
try {
|
|
973
1000
|
const { titleSource, ...threadDataPayload } = data;
|
|
974
1001
|
const localThread = threadsRef.current.find((t) => t.id === id);
|
|
@@ -1004,6 +1031,13 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
1004
1031
|
}
|
|
1005
1032
|
if (!response.ok)
|
|
1006
1033
|
return;
|
|
1034
|
+
const reportedScope = savedThreadScope(
|
|
1035
|
+
// coercion-ok: a save response without a readable body carries no scope, and the local scope stays as it was.
|
|
1036
|
+
await response.json().catch(() => null));
|
|
1037
|
+
// A response that was in flight across a detach describes the thread
|
|
1038
|
+
// as it was before it, so it must not put the old scope back.
|
|
1039
|
+
const scopeChangedDuringSave = (scopeMutationsRef.current.get(id) ?? 0) !== scopeEpoch;
|
|
1040
|
+
const savedScope = scopeChangedDuringSave ? undefined : reportedScope;
|
|
1007
1041
|
serverConfirmedThreadIdsRef.current.add(id);
|
|
1008
1042
|
clearClientDraftThreadMarker(id);
|
|
1009
1043
|
newlyCreatedRef.current.delete(id);
|
|
@@ -1021,10 +1055,21 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
1021
1055
|
...(data.messageCount != null && {
|
|
1022
1056
|
messageCount: data.messageCount,
|
|
1023
1057
|
}),
|
|
1058
|
+
// The run adopts the scope it was sent with, which the
|
|
1059
|
+
// visible page at save time may no longer be; take the
|
|
1060
|
+
// server's, or the active pointer stays under the
|
|
1061
|
+
// unscoped key and a reload here starts fresh.
|
|
1062
|
+
...(savedScope !== undefined
|
|
1063
|
+
? { scope: savedScope }
|
|
1064
|
+
: {}),
|
|
1024
1065
|
updatedAt: Date.now(),
|
|
1025
1066
|
}
|
|
1026
1067
|
: t));
|
|
1027
1068
|
}
|
|
1069
|
+
// A thread the list no longer holds because it was detached while
|
|
1070
|
+
// this save ran must not come back under the page's current scope.
|
|
1071
|
+
if (scopeChangedDuringSave)
|
|
1072
|
+
return prev;
|
|
1028
1073
|
const now = Date.now();
|
|
1029
1074
|
return sortThreadSummaries([
|
|
1030
1075
|
{
|
|
@@ -1034,7 +1079,9 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
1034
1079
|
messageCount: data.messageCount ?? 0,
|
|
1035
1080
|
createdAt: now,
|
|
1036
1081
|
updatedAt: now,
|
|
1037
|
-
scope:
|
|
1082
|
+
scope: savedScope !== undefined
|
|
1083
|
+
? savedScope
|
|
1084
|
+
: (scopeRef.current ?? null),
|
|
1038
1085
|
},
|
|
1039
1086
|
...prev,
|
|
1040
1087
|
]);
|
|
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
38
38
|
error: string;
|
|
39
39
|
states?: undefined;
|
|
40
40
|
} | {
|
|
41
|
-
error?: undefined;
|
|
42
41
|
states: {
|
|
43
42
|
clientId: number;
|
|
44
43
|
state: string;
|
|
45
44
|
}[];
|
|
45
|
+
error?: undefined;
|
|
46
46
|
}>>;
|
|
47
47
|
export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
48
48
|
error: string;
|
|
49
49
|
users?: undefined;
|
|
50
50
|
} | {
|
|
51
|
-
error?: undefined;
|
|
52
51
|
users: {
|
|
53
52
|
clientId: number;
|
|
54
53
|
lastSeen: number;
|
|
55
54
|
}[];
|
|
55
|
+
error?: undefined;
|
|
56
56
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
8
8
|
state: string;
|
|
9
9
|
}>>;
|
|
10
10
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
ok?: undefined;
|
|
12
11
|
error: string;
|
|
12
|
+
ok?: undefined;
|
|
13
13
|
} | {
|
|
14
14
|
error?: undefined;
|
|
15
15
|
ok: boolean;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
2
|
-
error?: undefined;
|
|
3
2
|
count: number;
|
|
4
3
|
updated?: undefined;
|
|
4
|
+
error?: undefined;
|
|
5
5
|
ok?: undefined;
|
|
6
6
|
} | {
|
|
7
|
-
error?: undefined;
|
|
8
7
|
count?: undefined;
|
|
9
8
|
updated: number;
|
|
9
|
+
error?: undefined;
|
|
10
10
|
ok?: undefined;
|
|
11
11
|
} | {
|
|
12
12
|
count?: undefined;
|
|
@@ -14,8 +14,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
14
14
|
error: string;
|
|
15
15
|
ok?: undefined;
|
|
16
16
|
} | {
|
|
17
|
-
error?: undefined;
|
|
18
17
|
count?: undefined;
|
|
19
18
|
updated?: undefined;
|
|
20
19
|
ok: boolean;
|
|
20
|
+
error?: undefined;
|
|
21
21
|
}>>;
|
|
@@ -27,38 +27,38 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
27
27
|
thumbsUpRate: number;
|
|
28
28
|
avgEvalScore: number;
|
|
29
29
|
} | {
|
|
30
|
+
ok?: undefined;
|
|
30
31
|
error: string;
|
|
31
32
|
message: string;
|
|
32
33
|
summary?: undefined;
|
|
33
34
|
spans?: undefined;
|
|
34
35
|
id?: undefined;
|
|
35
|
-
ok?: undefined;
|
|
36
36
|
} | {
|
|
37
|
+
error?: undefined;
|
|
38
|
+
ok?: undefined;
|
|
37
39
|
message?: undefined;
|
|
38
40
|
summary: import("./types.js").TraceSummary;
|
|
39
41
|
spans: import("./types.js").TraceSpan[];
|
|
40
42
|
id?: undefined;
|
|
43
|
+
} | {
|
|
41
44
|
error?: undefined;
|
|
42
45
|
ok?: undefined;
|
|
43
|
-
} | {
|
|
44
46
|
message?: undefined;
|
|
45
47
|
summary?: undefined;
|
|
46
48
|
spans?: undefined;
|
|
47
49
|
id: string;
|
|
48
|
-
error?: undefined;
|
|
49
|
-
ok?: undefined;
|
|
50
50
|
} | {
|
|
51
|
+
ok?: undefined;
|
|
51
52
|
message?: undefined;
|
|
52
53
|
summary?: undefined;
|
|
53
54
|
spans?: undefined;
|
|
54
55
|
id?: undefined;
|
|
55
56
|
error: any;
|
|
56
|
-
ok?: undefined;
|
|
57
57
|
} | {
|
|
58
|
+
error?: undefined;
|
|
58
59
|
message?: undefined;
|
|
59
60
|
summary?: undefined;
|
|
60
61
|
spans?: undefined;
|
|
61
62
|
id?: undefined;
|
|
62
63
|
ok: boolean;
|
|
63
|
-
error?: undefined;
|
|
64
64
|
}>>;
|
|
@@ -39,8 +39,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
39
39
|
error: string;
|
|
40
40
|
}>;
|
|
41
41
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
42
|
-
ok?: undefined;
|
|
43
42
|
error: string;
|
|
43
|
+
ok?: undefined;
|
|
44
44
|
} | {
|
|
45
45
|
error?: undefined;
|
|
46
46
|
ok: boolean;
|
|
@@ -5040,7 +5040,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5040
5040
|
: null;
|
|
5041
5041
|
const { isBuilderGatewayDeployConfigured } = await import("./credential-provider.js");
|
|
5042
5042
|
return {
|
|
5043
|
-
active:
|
|
5043
|
+
active: run.inFlight,
|
|
5044
5044
|
runId: run.runId,
|
|
5045
5045
|
threadId: run.threadId,
|
|
5046
5046
|
turnId: run.turnId,
|
|
@@ -5383,7 +5383,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5383
5383
|
const incomingScope = parseScopeFromBody(body.scope);
|
|
5384
5384
|
await setThreadScope(threadId, owner, incomingScope);
|
|
5385
5385
|
}
|
|
5386
|
-
|
|
5386
|
+
// The scope the thread really has now (a detach can land
|
|
5387
|
+
// between the read above and this save), so the client records
|
|
5388
|
+
// what the server holds instead of guessing from the page.
|
|
5389
|
+
const saved = await resolveThreadAccess(owner, threadId, "editor", { orgId });
|
|
5390
|
+
return { ok: true, scope: saved?.scope ?? null };
|
|
5387
5391
|
});
|
|
5388
5392
|
}
|
|
5389
5393
|
// POST /threads/:id/queued — apply a single queue mutation against
|
|
@@ -66,12 +66,12 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
|
|
|
66
66
|
code: any;
|
|
67
67
|
} | {
|
|
68
68
|
errorCode?: undefined;
|
|
69
|
+
error?: undefined;
|
|
69
70
|
code?: undefined;
|
|
70
71
|
ok: boolean;
|
|
71
72
|
key: string;
|
|
72
73
|
baseUrlKey?: string;
|
|
73
74
|
scope: AgentEngineApiKeyScope;
|
|
74
75
|
defaultModel?: import("./agent-engine-default-model-route.js").SavedKeyDefaultModelOutcome;
|
|
75
|
-
error?: undefined;
|
|
76
76
|
}>>;
|
|
77
77
|
export {};
|
|
@@ -8,17 +8,17 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
|
|
|
8
8
|
* resolveEngine's credential detection.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
ok?: undefined;
|
|
12
11
|
error: string;
|
|
13
12
|
scope?: undefined;
|
|
13
|
+
ok?: undefined;
|
|
14
14
|
} | {
|
|
15
15
|
ok: boolean;
|
|
16
16
|
error: any;
|
|
17
17
|
scope?: undefined;
|
|
18
18
|
} | {
|
|
19
|
-
error?: undefined;
|
|
20
19
|
ok: boolean;
|
|
21
20
|
scope: "org" | "user";
|
|
21
|
+
error?: undefined;
|
|
22
22
|
}>>;
|
|
23
23
|
export interface DefaultModelSelectionRequest {
|
|
24
24
|
engine: string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
models?: undefined;
|
|
4
3
|
ok?: undefined;
|
|
4
|
+
models?: undefined;
|
|
5
5
|
} | {
|
|
6
|
+
error?: undefined;
|
|
6
7
|
ok: boolean;
|
|
7
8
|
models: string[];
|
|
8
|
-
error?: undefined;
|
|
9
9
|
}>>;
|
|
@@ -626,8 +626,8 @@ export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDi
|
|
|
626
626
|
error: string;
|
|
627
627
|
agents?: undefined;
|
|
628
628
|
} | {
|
|
629
|
-
agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
|
|
630
629
|
error?: undefined;
|
|
630
|
+
agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
|
|
631
631
|
}>>;
|
|
632
632
|
export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null;
|
|
633
633
|
export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string;
|
|
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
54
54
|
expiresAt?: undefined;
|
|
55
55
|
ttlSeconds?: undefined;
|
|
56
56
|
} | {
|
|
57
|
-
error?: undefined;
|
|
58
57
|
token: string;
|
|
59
58
|
expiresAt: string;
|
|
60
59
|
ttlSeconds: number;
|
|
60
|
+
error?: undefined;
|
|
61
61
|
}>>;
|
|
@@ -14,6 +14,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
14
14
|
executionCwd?: string;
|
|
15
15
|
}, {
|
|
16
16
|
deleted?: undefined;
|
|
17
|
+
enabled?: undefined;
|
|
17
18
|
created: boolean;
|
|
18
19
|
name: string;
|
|
19
20
|
scope: "organization" | "personal";
|
|
@@ -24,25 +25,24 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
24
25
|
reasoningEffort: "auto" | "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh";
|
|
25
26
|
webhookPath: string;
|
|
26
27
|
nextRun: string;
|
|
27
|
-
enabled?: undefined;
|
|
28
28
|
executionHostId?: undefined;
|
|
29
29
|
executionEngine?: undefined;
|
|
30
30
|
executionCwd?: undefined;
|
|
31
31
|
} | {
|
|
32
|
+
enabled?: undefined;
|
|
33
|
+
nextRun?: undefined;
|
|
32
34
|
created?: undefined;
|
|
33
35
|
scope?: undefined;
|
|
34
36
|
triggerType?: undefined;
|
|
35
37
|
event?: undefined;
|
|
36
38
|
deleted: boolean;
|
|
37
39
|
name: string;
|
|
38
|
-
enabled?: undefined;
|
|
39
40
|
schedule?: undefined;
|
|
40
41
|
timezone?: undefined;
|
|
41
42
|
reasoningEffort?: undefined;
|
|
42
43
|
executionHostId?: undefined;
|
|
43
44
|
executionEngine?: undefined;
|
|
44
45
|
executionCwd?: undefined;
|
|
45
|
-
nextRun?: undefined;
|
|
46
46
|
webhookPath?: undefined;
|
|
47
47
|
} | {
|
|
48
48
|
deleted?: undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.200.
|
|
3
|
+
"version": "0.200.1-nightly-20261002183718",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -668,7 +668,7 @@
|
|
|
668
668
|
"yaml": "^2.9.0",
|
|
669
669
|
"yjs": "^13.6.33",
|
|
670
670
|
"zod": "^4.3.6",
|
|
671
|
-
"@agent-native/agentkit": "^0.200.
|
|
671
|
+
"@agent-native/agentkit": "^0.200.1-nightly-20261002183718",
|
|
672
672
|
"@agent-native/recap-cli": "^0.5.60"
|
|
673
673
|
},
|
|
674
674
|
"devDependencies": {
|
|
@@ -739,7 +739,7 @@
|
|
|
739
739
|
"xlsx": "^0.18.5"
|
|
740
740
|
},
|
|
741
741
|
"peerDependencies": {
|
|
742
|
-
"@agent-native/core-corpus": "
|
|
742
|
+
"@agent-native/core-corpus": "0.200.1-nightly-20261002183718",
|
|
743
743
|
"@ai-sdk/anthropic": ">=3",
|
|
744
744
|
"@ai-sdk/cohere": ">=3",
|
|
745
745
|
"@ai-sdk/google": ">=3",
|