@agent-native/core 0.12.9 → 0.12.11
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/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +10 -2
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.d.ts +2 -2
- package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.js +19 -2
- package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
- package/dist/agent/engine/types.d.ts +9 -0
- package/dist/agent/engine/types.d.ts.map +1 -1
- package/dist/agent/engine/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts +2 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +202 -4
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/types.d.ts +32 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/workspace-dev.js +17 -0
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +74 -5
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +1 -0
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +147 -7
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +3 -2
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/pasted-text.d.ts.map +1 -1
- package/dist/client/composer/pasted-text.js +5 -6
- package/dist/client/composer/pasted-text.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +4 -4
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/frame.d.ts +8 -0
- package/dist/client/frame.d.ts.map +1 -1
- package/dist/client/frame.js +34 -0
- package/dist/client/frame.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +5 -3
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.js +2 -1
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +1 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +15 -37
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/deploy/workspace-deploy.js +4 -0
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +10 -1
- package/dist/extensions/routes.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +51 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +19 -1
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/oauth-state.d.ts +10 -0
- package/dist/shared/oauth-state.d.ts.map +1 -0
- package/dist/shared/oauth-state.js +32 -0
- package/dist/shared/oauth-state.js.map +1 -0
- package/dist/templates/default/app/entry.client.tsx +12 -0
- package/dist/templates/default/app/root.tsx +4 -1
- package/dist/templates/workspace-core/AGENTS.md +11 -0
- package/dist/templates/workspace-root/AGENTS.md +11 -0
- package/dist/templates/workspace-root/README.md +7 -1
- package/package.json +1 -1
- package/src/templates/default/app/entry.client.tsx +12 -0
- package/src/templates/default/app/root.tsx +4 -1
- package/src/templates/workspace-core/AGENTS.md +11 -0
- package/src/templates/workspace-root/AGENTS.md +11 -0
- package/src/templates/workspace-root/README.md +7 -1
|
@@ -297,9 +297,13 @@ export function createPlanModeActionRegistry(actions) {
|
|
|
297
297
|
}
|
|
298
298
|
const MAX_RETRIES = 3;
|
|
299
299
|
const RETRY_BASE_DELAY_MS = 2000;
|
|
300
|
+
const TOOL_INPUT_ACTIVITY_INTERVAL_MS = 1500;
|
|
300
301
|
function generateRunId() {
|
|
301
302
|
return `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
302
303
|
}
|
|
304
|
+
function toolInputActivityLabel(toolName) {
|
|
305
|
+
return toolName ? `Preparing ${toolName} action` : "Preparing action input";
|
|
306
|
+
}
|
|
303
307
|
/** Check if an error is transient and should be retried */
|
|
304
308
|
function isContextTooLongError(err) {
|
|
305
309
|
if (!(err instanceof Error))
|
|
@@ -429,6 +433,69 @@ export function buildUserContentWithAttachments(opts) {
|
|
|
429
433
|
});
|
|
430
434
|
return userContent;
|
|
431
435
|
}
|
|
436
|
+
export function structuredHistoryToEngineMessages(history) {
|
|
437
|
+
if (!Array.isArray(history))
|
|
438
|
+
return null;
|
|
439
|
+
const messages = [];
|
|
440
|
+
for (const message of history) {
|
|
441
|
+
if (!message ||
|
|
442
|
+
(message.role !== "user" && message.role !== "assistant") ||
|
|
443
|
+
!Array.isArray(message.content)) {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
const content = [];
|
|
447
|
+
for (const part of message.content) {
|
|
448
|
+
if (!part || typeof part !== "object")
|
|
449
|
+
continue;
|
|
450
|
+
if (part.type === "text" && typeof part.text === "string") {
|
|
451
|
+
if (part.text.length > 0) {
|
|
452
|
+
content.push({ type: "text", text: part.text });
|
|
453
|
+
}
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (part.type === "tool-call" && message.role === "assistant") {
|
|
457
|
+
const id = typeof part.id === "string"
|
|
458
|
+
? part.id
|
|
459
|
+
: typeof part.toolCallId === "string"
|
|
460
|
+
? part.toolCallId
|
|
461
|
+
: "";
|
|
462
|
+
const name = typeof part.name === "string"
|
|
463
|
+
? part.name
|
|
464
|
+
: typeof part.toolName === "string"
|
|
465
|
+
? part.toolName
|
|
466
|
+
: "";
|
|
467
|
+
if (!id || !name)
|
|
468
|
+
continue;
|
|
469
|
+
content.push({
|
|
470
|
+
type: "tool-call",
|
|
471
|
+
id,
|
|
472
|
+
name,
|
|
473
|
+
input: part.input ?? part.args ?? {},
|
|
474
|
+
});
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (part.type === "tool-result" && message.role === "user") {
|
|
478
|
+
if (typeof part.toolCallId !== "string" ||
|
|
479
|
+
typeof part.content !== "string") {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
content.push({
|
|
483
|
+
type: "tool-result",
|
|
484
|
+
toolCallId: part.toolCallId,
|
|
485
|
+
...(typeof part.toolName === "string"
|
|
486
|
+
? { toolName: part.toolName }
|
|
487
|
+
: {}),
|
|
488
|
+
content: part.content,
|
|
489
|
+
...(part.isError ? { isError: true } : {}),
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (content.length > 0) {
|
|
494
|
+
messages.push({ role: message.role, content });
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return messages.length > 0 ? messages : null;
|
|
498
|
+
}
|
|
432
499
|
/** Build enriched message with file/skill/mention references */
|
|
433
500
|
function enrichMessage(message, references) {
|
|
434
501
|
if (references.length === 0)
|
|
@@ -487,6 +554,52 @@ export function appendAgentLoopContinuation(messages, reason) {
|
|
|
487
554
|
],
|
|
488
555
|
});
|
|
489
556
|
}
|
|
557
|
+
function textFromEngineMessage(message) {
|
|
558
|
+
return message.content
|
|
559
|
+
.filter((part) => part.type === "text")
|
|
560
|
+
.map((part) => part.text)
|
|
561
|
+
.join("\n");
|
|
562
|
+
}
|
|
563
|
+
function isInternalContinuationTurn(messages) {
|
|
564
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
565
|
+
const message = messages[i];
|
|
566
|
+
if (message.role !== "user")
|
|
567
|
+
continue;
|
|
568
|
+
return textFromEngineMessage(message).startsWith(AGENT_INTERNAL_CONTINUE_PROMPT);
|
|
569
|
+
}
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
function seedReadOnlyToolResultsFromHistory(messages, actions) {
|
|
573
|
+
const cache = new Map();
|
|
574
|
+
if (!isInternalContinuationTurn(messages))
|
|
575
|
+
return cache;
|
|
576
|
+
const pendingToolCalls = new Map();
|
|
577
|
+
for (const message of messages) {
|
|
578
|
+
if (message.role === "assistant") {
|
|
579
|
+
for (const part of message.content) {
|
|
580
|
+
if (part.type !== "tool-call")
|
|
581
|
+
continue;
|
|
582
|
+
const entry = actions[part.name];
|
|
583
|
+
if (entry?.readOnly !== true)
|
|
584
|
+
continue;
|
|
585
|
+
pendingToolCalls.set(part.id, {
|
|
586
|
+
name: part.name,
|
|
587
|
+
input: part.input,
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
for (const part of message.content) {
|
|
593
|
+
if (part.type !== "tool-result")
|
|
594
|
+
continue;
|
|
595
|
+
const call = pendingToolCalls.get(part.toolCallId);
|
|
596
|
+
if (!call)
|
|
597
|
+
continue;
|
|
598
|
+
cache.set(toolCallCacheKey(call.name, call.input), part.content);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return cache;
|
|
602
|
+
}
|
|
490
603
|
/**
|
|
491
604
|
* Convert ActionEntry registry to EngineTool array.
|
|
492
605
|
*/
|
|
@@ -531,6 +644,22 @@ function stringifyToolInput(input) {
|
|
|
531
644
|
return String(input);
|
|
532
645
|
}
|
|
533
646
|
}
|
|
647
|
+
function stableStringify(value) {
|
|
648
|
+
if (value === null || typeof value !== "object") {
|
|
649
|
+
return JSON.stringify(value);
|
|
650
|
+
}
|
|
651
|
+
if (Array.isArray(value)) {
|
|
652
|
+
return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
653
|
+
}
|
|
654
|
+
const obj = value;
|
|
655
|
+
return `{${Object.keys(obj)
|
|
656
|
+
.sort()
|
|
657
|
+
.map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`)
|
|
658
|
+
.join(",")}}`;
|
|
659
|
+
}
|
|
660
|
+
function toolCallCacheKey(toolName, input) {
|
|
661
|
+
return `${toolName}:${stableStringify(normalizeToolCallInputForHistory(input))}`;
|
|
662
|
+
}
|
|
534
663
|
function normalizeToolCallInputForHistory(input) {
|
|
535
664
|
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
536
665
|
return input;
|
|
@@ -564,6 +693,8 @@ export async function runAgentLoop(opts) {
|
|
|
564
693
|
runCtx.toolCalls = toolCallHistory;
|
|
565
694
|
runCtx.toolResults = toolResultHistory;
|
|
566
695
|
}
|
|
696
|
+
const readOnlyToolResultCache = seedReadOnlyToolResultsFromHistory(messages, actions);
|
|
697
|
+
const duplicateReadOnlyToolCalls = new Map();
|
|
567
698
|
let finalGuardRetries = 0;
|
|
568
699
|
let iterations = 0;
|
|
569
700
|
while (true) {
|
|
@@ -590,6 +721,21 @@ export async function runAgentLoop(opts) {
|
|
|
590
721
|
};
|
|
591
722
|
const eventStream = engine.stream(streamOpts);
|
|
592
723
|
let thinkingBuffer = "";
|
|
724
|
+
const toolInputNames = new Map();
|
|
725
|
+
let lastToolInputActivityAt = 0;
|
|
726
|
+
const sendToolInputActivity = (toolName, force = false) => {
|
|
727
|
+
const now = Date.now();
|
|
728
|
+
if (!force &&
|
|
729
|
+
now - lastToolInputActivityAt < TOOL_INPUT_ACTIVITY_INTERVAL_MS) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
lastToolInputActivityAt = now;
|
|
733
|
+
send({
|
|
734
|
+
type: "activity",
|
|
735
|
+
label: toolInputActivityLabel(toolName),
|
|
736
|
+
...(toolName ? { tool: toolName } : {}),
|
|
737
|
+
});
|
|
738
|
+
};
|
|
593
739
|
for await (const event of eventStream) {
|
|
594
740
|
if (event.type === "text-delta") {
|
|
595
741
|
send({ type: "text", text: event.text });
|
|
@@ -600,6 +746,17 @@ export async function runAgentLoop(opts) {
|
|
|
600
746
|
// we accumulate them. In a future iteration, we can surface
|
|
601
747
|
// them as a collapsible "reasoning" section in the UI.
|
|
602
748
|
}
|
|
749
|
+
else if (event.type === "tool-input-start") {
|
|
750
|
+
if (event.id && event.name) {
|
|
751
|
+
toolInputNames.set(event.id, event.name);
|
|
752
|
+
}
|
|
753
|
+
sendToolInputActivity(event.name, true);
|
|
754
|
+
}
|
|
755
|
+
else if (event.type === "tool-input-delta") {
|
|
756
|
+
const toolName = event.name ??
|
|
757
|
+
(event.id ? toolInputNames.get(event.id) : undefined);
|
|
758
|
+
sendToolInputActivity(toolName);
|
|
759
|
+
}
|
|
603
760
|
else if (event.type === "tool-call") {
|
|
604
761
|
// The authoritative tool-call blocks arrive in assistant-content.
|
|
605
762
|
}
|
|
@@ -734,6 +891,36 @@ export async function runAgentLoop(opts) {
|
|
|
734
891
|
isError: true,
|
|
735
892
|
};
|
|
736
893
|
}
|
|
894
|
+
const cacheKey = actionEntry.readOnly === true
|
|
895
|
+
? toolCallCacheKey(toolCall.name, toolCall.input)
|
|
896
|
+
: null;
|
|
897
|
+
if (cacheKey && readOnlyToolResultCache.has(cacheKey)) {
|
|
898
|
+
const repeats = (duplicateReadOnlyToolCalls.get(cacheKey) ?? 0) + 1;
|
|
899
|
+
duplicateReadOnlyToolCalls.set(cacheKey, repeats);
|
|
900
|
+
const previousResult = readOnlyToolResultCache.get(cacheKey) ?? "";
|
|
901
|
+
const result = `Skipped duplicate read-only call to ${toolCall.name}: identical input already ran in this turn. ` +
|
|
902
|
+
`Use the previous result already in the conversation instead of calling this tool again.\n\n` +
|
|
903
|
+
`Previous result:\n${previousResult}`;
|
|
904
|
+
send({
|
|
905
|
+
type: "tool_start",
|
|
906
|
+
tool: toolCall.name,
|
|
907
|
+
input: toolCall.input,
|
|
908
|
+
});
|
|
909
|
+
send({ type: "tool_done", tool: toolCall.name, result });
|
|
910
|
+
recordToolResult(result, false);
|
|
911
|
+
if (repeats >= 3) {
|
|
912
|
+
requestedActionStop ??= {
|
|
913
|
+
message: "I stopped because the agent kept asking for the same read-only context it already had. Please send the request again if you want me to retry from a fresh turn.",
|
|
914
|
+
errorCode: "duplicate_read_only_tool",
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
return {
|
|
918
|
+
type: "tool-result",
|
|
919
|
+
toolCallId: toolCall.id,
|
|
920
|
+
toolName: toolCall.name,
|
|
921
|
+
content: result,
|
|
922
|
+
};
|
|
923
|
+
}
|
|
737
924
|
send({
|
|
738
925
|
type: "tool_start",
|
|
739
926
|
tool: toolCall.name,
|
|
@@ -823,6 +1010,15 @@ export async function runAgentLoop(opts) {
|
|
|
823
1010
|
}
|
|
824
1011
|
send({ type: "tool_done", tool: toolCall.name, result });
|
|
825
1012
|
recordToolResult(result, isError);
|
|
1013
|
+
if (!isError) {
|
|
1014
|
+
if (cacheKey) {
|
|
1015
|
+
readOnlyToolResultCache.set(cacheKey, result);
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
readOnlyToolResultCache.clear();
|
|
1019
|
+
duplicateReadOnlyToolCalls.clear();
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
826
1022
|
return {
|
|
827
1023
|
type: "tool-result",
|
|
828
1024
|
toolCallId: toolCall.id,
|
|
@@ -913,7 +1109,7 @@ export function createProductionAgentHandler(options) {
|
|
|
913
1109
|
setResponseStatus(event, 400);
|
|
914
1110
|
return { error: "Invalid request body" };
|
|
915
1111
|
}
|
|
916
|
-
const { message, history = [], references = [], threadId, attachments, model: requestModel, engine: requestEngine, effort: requestEffort, } = body;
|
|
1112
|
+
const { message, history = [], structuredHistory, references = [], threadId, attachments, model: requestModel, engine: requestEngine, effort: requestEffort, } = body;
|
|
917
1113
|
const requestMode = body.mode === "plan" ? "plan" : "act";
|
|
918
1114
|
const hasMessageText = typeof message === "string" && message.trim().length > 0;
|
|
919
1115
|
const hasAttachments = Array.isArray(attachments) && attachments.length > 0;
|
|
@@ -1210,13 +1406,15 @@ export function createProductionAgentHandler(options) {
|
|
|
1210
1406
|
text: enrichedMessage + screenContext + filesContext + planModeAgentNote,
|
|
1211
1407
|
attachments,
|
|
1212
1408
|
});
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1409
|
+
const historyMessages = structuredHistoryToEngineMessages(structuredHistory) ??
|
|
1410
|
+
history
|
|
1215
1411
|
.filter((m) => m.content.trim())
|
|
1216
1412
|
.map((m) => ({
|
|
1217
1413
|
role: m.role,
|
|
1218
1414
|
content: [{ type: "text", text: m.content }],
|
|
1219
|
-
}))
|
|
1415
|
+
}));
|
|
1416
|
+
const messages = [
|
|
1417
|
+
...historyMessages,
|
|
1220
1418
|
{ role: "user", content: userContent },
|
|
1221
1419
|
];
|
|
1222
1420
|
// If there's already an active run for this thread, reject with 409 so
|