@agent-native/core 0.84.18 → 0.84.21
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +21 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/caller-auth.ts +37 -8
- package/corpus/core/src/a2a/client.ts +178 -67
- package/corpus/core/src/agent/production-agent.ts +19 -3
- package/corpus/core/src/agent/run-store.ts +180 -13
- package/corpus/core/src/agent/types.ts +1 -1
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +1 -1
- package/corpus/core/src/cli/recap.ts +43 -34
- package/corpus/core/src/client/AssistantChat.tsx +49 -0
- package/corpus/core/src/client/PoweredByBadge.tsx +70 -17
- package/corpus/core/src/client/active-run-state.ts +30 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +5 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +41 -3
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +133 -0
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +2 -2
- package/corpus/core/src/client/i18n.tsx +10 -5
- package/corpus/core/src/client/sse-event-processor.ts +147 -5
- package/corpus/core/src/extensions/html-shell.ts +17 -3
- package/corpus/core/src/extensions/theme.ts +39 -0
- package/corpus/core/src/file-upload/builder.ts +35 -14
- package/corpus/core/src/file-upload/types.ts +3 -0
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +49 -24
- package/corpus/core/src/mcp/builtin-tools.ts +3 -0
- package/corpus/core/src/mcp/org-directory.ts +66 -20
- package/corpus/core/src/scripts/call-agent.ts +7 -2
- package/corpus/templates/analytics/actions/provider-api-request.ts +8 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +91 -33
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +161 -12
- package/corpus/templates/analytics/changelog/2026-07-01-session-replays-load-large-production-recordings-from-scoped.md +6 -0
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +14 -8
- package/corpus/templates/calendar/changelog/2026-07-01-meeting-invite-pages-have-cleaner-branding-a-black-dark-mo.md +6 -0
- package/corpus/templates/clips/actions/create-recording.ts +7 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +11 -0
- package/corpus/templates/clips/actions/get-recording-player-data.ts +4 -2
- package/corpus/templates/clips/actions/import-loom-recording.ts +1 -0
- package/corpus/templates/clips/actions/lib/loom-video.ts +16 -0
- package/corpus/templates/clips/app/components/player/scrubber.tsx +2 -2
- package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +4 -3
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +39 -12
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +65 -1
- package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +1 -22
- package/corpus/templates/clips/app/routes/record.tsx +48 -8
- package/corpus/templates/clips/changelog/2026-07-01-chrome-recording-uploads-now-serialize-chunks-to-avoid-resum.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-clip-uploads-and-loom-imports-finish-sooner-by-skipping-the-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-clip-uploads-and-playback-recover-more-reliably-from-storage.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-desktop-recording-avoids-unsupported-browser-tab-capture.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-embedded-player-progress-is-easier-to-see-on-dark-videos.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-loom-imports-show-clear-guidance-when-loom-does-not-provide-a-downloadable-video.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-preserve-in-flight-streaming-uploads-when-the-streaming-kill.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-recording-controls-are-cleaner-and-the-countdown-uses-shadow.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-recordings-now-recover-when-final-upload-status-gets-lost.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +7 -224
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +94 -29
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +87 -5
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +7 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +14 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +96 -1
- package/corpus/templates/clips/shared/finalize-recovery.ts +242 -0
- package/corpus/templates/design/changelog/2026-07-01-design-recovers-sooner-when-an-agent-gets-stuck-preparing-a-.md +6 -0
- package/corpus/templates/plan/app/global.css +1 -1
- package/dist/a2a/caller-auth.d.ts +1 -0
- package/dist/a2a/caller-auth.d.ts.map +1 -1
- package/dist/a2a/caller-auth.js +34 -8
- package/dist/a2a/caller-auth.js.map +1 -1
- package/dist/a2a/client.d.ts +4 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +148 -58
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +19 -4
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +19 -6
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +163 -13
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +1 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +3 -3
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +41 -34
- package/dist/cli/recap.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +36 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/PoweredByBadge.d.ts +9 -3
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +47 -15
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/active-run-state.d.ts +3 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +24 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +5 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +32 -3
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +59 -2
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +2 -2
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/i18n.d.ts +1 -1
- package/dist/client/i18n.d.ts.map +1 -1
- package/dist/client/i18n.js +6 -2
- package/dist/client/i18n.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +2 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +121 -5
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +17 -3
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/theme.d.ts +9 -0
- package/dist/extensions/theme.d.ts.map +1 -1
- package/dist/extensions/theme.js +38 -0
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +22 -8
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/file-upload/types.d.ts +5 -1
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +43 -18
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +3 -0
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +58 -20
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +2 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* thin, deterministic glue around that:
|
|
9
9
|
*
|
|
10
10
|
* gate The security boundary: decide whether the recap runs at all
|
|
11
|
-
* (skipping drafts, forks, bots, missing
|
|
12
|
-
* agent/model, and PRs that touch
|
|
13
|
-
* normalized backend agent to use.
|
|
11
|
+
* (skipping drafts, forks without secret access, bots, missing
|
|
12
|
+
* secrets, an invalid agent/model, and untrusted PRs that touch
|
|
13
|
+
* recap-control files) and which normalized backend agent to use.
|
|
14
14
|
* collect-diff Collect the bounded base...head diff (excluding lockfiles,
|
|
15
15
|
* build output, snapshots), cap it at ~600KB, and classify the
|
|
16
16
|
* huge/tiny flags.
|
|
@@ -2846,7 +2846,14 @@ export async function runShot(
|
|
|
2846
2846
|
});
|
|
2847
2847
|
}
|
|
2848
2848
|
const page = await context.newPage();
|
|
2849
|
-
await page.goto(captureUrl, {
|
|
2849
|
+
await page.goto(captureUrl, {
|
|
2850
|
+
waitUntil: "domcontentloaded",
|
|
2851
|
+
timeout: 45_000,
|
|
2852
|
+
});
|
|
2853
|
+
await page.waitForLoadState("load", { timeout: 15_000 }).catch(() => {
|
|
2854
|
+
// The selectors below are the real readiness signal for screenshots.
|
|
2855
|
+
// Some recap pages keep long-lived/background requests open.
|
|
2856
|
+
});
|
|
2850
2857
|
const selectors = [
|
|
2851
2858
|
"[data-plan-document]",
|
|
2852
2859
|
"[data-plan-block]",
|
|
@@ -3104,11 +3111,11 @@ export interface RecapGateInput {
|
|
|
3104
3111
|
}
|
|
3105
3112
|
|
|
3106
3113
|
/**
|
|
3107
|
-
* Files that, if
|
|
3108
|
-
* instructions or agent config the trusted recap job
|
|
3109
|
-
* the recap CLI from trusted base-branch source (or an
|
|
3110
|
-
*
|
|
3111
|
-
* recapped without executing PR-modified CLI code.
|
|
3114
|
+
* Files that, if an untrusted PR touches them, would let that PR rewrite
|
|
3115
|
+
* repo-pinned skill instructions or root agent config the trusted recap job
|
|
3116
|
+
* loads. The workflow runs the recap CLI from trusted base-branch source (or an
|
|
3117
|
+
* installed package), so normal package code, template-local AGENTS.md files,
|
|
3118
|
+
* and recap workflow YAML can be recapped without executing PR-modified CLI code.
|
|
3112
3119
|
*/
|
|
3113
3120
|
function normalizeRecapSkillSourceMode(value: string | undefined): string {
|
|
3114
3121
|
return (value || "auto").toLowerCase();
|
|
@@ -3124,10 +3131,10 @@ export function isRecapSensitivePath(
|
|
|
3124
3131
|
): boolean {
|
|
3125
3132
|
const skillSource = options.skillSource;
|
|
3126
3133
|
if (
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3134
|
+
p.startsWith(".claude/") ||
|
|
3135
|
+
p === "CLAUDE.md" ||
|
|
3136
|
+
p === "AGENTS.md" ||
|
|
3137
|
+
p === ".mcp.json"
|
|
3131
3138
|
) {
|
|
3132
3139
|
return true;
|
|
3133
3140
|
}
|
|
@@ -3227,16 +3234,18 @@ export function evaluateRecapGate(input: RecapGateInput): {
|
|
|
3227
3234
|
);
|
|
3228
3235
|
}
|
|
3229
3236
|
|
|
3230
|
-
// Self-modifying guard: if
|
|
3231
|
-
// when CI is explicitly pinned to repo-local skill instructions, or
|
|
3232
|
-
// config the runner would load (.claude/**, CLAUDE.md, AGENTS.md,
|
|
3233
|
-
// skip the ENTIRE job — not just the agent — so a PR can never
|
|
3234
|
-
// the agent loads (skill, hooks, settings) and exfiltrate the
|
|
3235
|
-
// secrets. In the default auto/latest modes the recap prompt comes
|
|
3236
|
-
// trusted bundled skill, so visual skill and recap workflow files are
|
|
3237
|
-
// reviewed content and may be recapped.
|
|
3237
|
+
// Self-modifying guard: if an untrusted PR changes the visual-recap/visual-plan
|
|
3238
|
+
// skill when CI is explicitly pinned to repo-local skill instructions, or root
|
|
3239
|
+
// agent config the runner would load (.claude/**, CLAUDE.md, AGENTS.md,
|
|
3240
|
+
// .mcp.json), skip the ENTIRE job — not just the agent — so a PR can never
|
|
3241
|
+
// rewrite what the agent loads (skill, hooks, settings) and exfiltrate the
|
|
3242
|
+
// publish/API secrets. In the default auto/latest modes the recap prompt comes
|
|
3243
|
+
// from the trusted bundled skill, so visual skill and recap workflow files are
|
|
3244
|
+
// ordinary reviewed content and may be recapped. Trusted write actors may edit
|
|
3245
|
+
// recap-control files as reviewable content; running the recap is useful signal
|
|
3246
|
+
// for those changes.
|
|
3238
3247
|
const shouldApplySensitivePathGuard =
|
|
3239
|
-
Boolean(pr) && (isFork ||
|
|
3248
|
+
Boolean(pr) && !isTrustedAuthor && (isFork || !isPrivate);
|
|
3240
3249
|
const hits = shouldApplySensitivePathGuard
|
|
3241
3250
|
? input.changedFiles.filter((p) => isRecapSensitivePath(p, { skillSource }))
|
|
3242
3251
|
: [];
|
|
@@ -3458,13 +3467,13 @@ export function appendGateSkipLine(
|
|
|
3458
3467
|
existingBody: string,
|
|
3459
3468
|
skipLine: string,
|
|
3460
3469
|
): string {
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
return `${
|
|
3470
|
+
const planIdMatch = existingBody.match(
|
|
3471
|
+
/<!--\s*plan-id:\s*([A-Za-z0-9_-]{1,64})\s*-->/,
|
|
3472
|
+
);
|
|
3473
|
+
const planIdMarker = planIdMatch
|
|
3474
|
+
? `\n\n<!-- plan-id: ${planIdMatch[1]} -->`
|
|
3475
|
+
: "";
|
|
3476
|
+
return `${buildGateSkipCommentBody()}${planIdMarker}\n\n${skipLine}`;
|
|
3468
3477
|
}
|
|
3469
3478
|
|
|
3470
3479
|
/* -------------------------------------------------------------------------- */
|
|
@@ -4095,11 +4104,11 @@ Usage:
|
|
|
4095
4104
|
environment (HAS_PLAN / HAS_ANTHROPIC / HAS_OPENAI === 'true', AGENT,
|
|
4096
4105
|
VISUAL_RECAP_MODEL), the repo from $GITHUB_REPOSITORY, and the PR's changed
|
|
4097
4106
|
files from the GitHub REST API (paged, with GH_TOKEN/GITHUB_TOKEN). Skips
|
|
4098
|
-
drafts, forks, bot authors, the missing-secret case, an
|
|
4099
|
-
and any PR that touches recap-control files
|
|
4100
|
-
.claude/**, CLAUDE.md, AGENTS.md,
|
|
4101
|
-
file-list error. Writes
|
|
4102
|
-
$GITHUB_OUTPUT.
|
|
4107
|
+
drafts, forks without secret access, bot authors, the missing-secret case, an
|
|
4108
|
+
invalid agent/model, and any untrusted PR that touches recap-control files
|
|
4109
|
+
(repo-pinned skill instructions, .claude/**, root CLAUDE.md, root AGENTS.md,
|
|
4110
|
+
root .mcp.json) — failing CLOSED on any file-list error. Writes
|
|
4111
|
+
run=<true|false> and agent=<claude|codex> to $GITHUB_OUTPUT.
|
|
4103
4112
|
npx @agent-native/core@latest recap agent-summary
|
|
4104
4113
|
Read the captured Claude/Codex result file and write a sanitized one-line
|
|
4105
4114
|
summary to stdout and $GITHUB_OUTPUT (summary). Used only when no plan URL
|
|
@@ -37,9 +37,11 @@ import React, {
|
|
|
37
37
|
import { LLM_MISSING_CREDENTIALS_MESSAGE } from "../agent/engine/credential-errors.js";
|
|
38
38
|
import type { ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
39
39
|
import {
|
|
40
|
+
getActiveRunActivityTool,
|
|
40
41
|
getActiveRun,
|
|
41
42
|
resolveReconnectAfterSeq,
|
|
42
43
|
setActiveRun,
|
|
44
|
+
updateActiveRunActivity,
|
|
43
45
|
updateActiveRunSeq,
|
|
44
46
|
} from "./active-run-state.js";
|
|
45
47
|
import {
|
|
@@ -553,6 +555,23 @@ function reconnectContentFollowKey(content: ContentPart[]): string {
|
|
|
553
555
|
return content.map(contentPartFollowKey).join("|");
|
|
554
556
|
}
|
|
555
557
|
|
|
558
|
+
export function reconnectActivityFallbackContent(
|
|
559
|
+
toolName: string | null | undefined,
|
|
560
|
+
): ContentPart[] {
|
|
561
|
+
const tool = toolName?.trim();
|
|
562
|
+
if (!tool) return [];
|
|
563
|
+
return [
|
|
564
|
+
{
|
|
565
|
+
type: "tool-call",
|
|
566
|
+
toolCallId: `reconnect-activity:${tool}`,
|
|
567
|
+
toolName: tool,
|
|
568
|
+
argsText: "",
|
|
569
|
+
args: {},
|
|
570
|
+
activity: true,
|
|
571
|
+
},
|
|
572
|
+
];
|
|
573
|
+
}
|
|
574
|
+
|
|
556
575
|
const RECOVERY_USER_MESSAGE_PREFIXES = [
|
|
557
576
|
"Continue from where you left off",
|
|
558
577
|
"Continue from where you stopped",
|
|
@@ -1395,6 +1414,9 @@ const AssistantChatInner = forwardRef<
|
|
|
1395
1414
|
const [runningActivityLabel, setRunningActivityLabel] = useState<
|
|
1396
1415
|
string | null
|
|
1397
1416
|
>(null);
|
|
1417
|
+
const [runningActivityTool, setRunningActivityTool] = useState<string | null>(
|
|
1418
|
+
null,
|
|
1419
|
+
);
|
|
1398
1420
|
// Delayed-reveal state for the activity label (see ACTIVITY_LABEL_REVEAL_DELAY_MS).
|
|
1399
1421
|
// `latest` holds the most recent activity label; `surfaced` flips true once the
|
|
1400
1422
|
// reveal timer fires; `timer` is the pending one-shot reveal.
|
|
@@ -1409,6 +1431,8 @@ const AssistantChatInner = forwardRef<
|
|
|
1409
1431
|
latestActivityLabelRef.current = null;
|
|
1410
1432
|
activityLabelSurfacedRef.current = false;
|
|
1411
1433
|
setRunningActivityLabel(null);
|
|
1434
|
+
setRunningActivityTool(null);
|
|
1435
|
+
updateActiveRunActivity(null);
|
|
1412
1436
|
}, []);
|
|
1413
1437
|
const [reconnectContent, setReconnectContent] = useState<ContentPart[]>([]);
|
|
1414
1438
|
// When stop is clicked during reconnect, keep content visible (don't wipe it)
|
|
@@ -1445,6 +1469,18 @@ const AssistantChatInner = forwardRef<
|
|
|
1445
1469
|
: isReconnecting && reconnectContent.length > 0
|
|
1446
1470
|
? "Reconnecting"
|
|
1447
1471
|
: "Thinking";
|
|
1472
|
+
const reconnectActivityContent = useMemo(
|
|
1473
|
+
() =>
|
|
1474
|
+
(isReconnecting || reconnectFrozen) && reconnectContent.length === 0
|
|
1475
|
+
? reconnectActivityFallbackContent(runningActivityTool)
|
|
1476
|
+
: [],
|
|
1477
|
+
[
|
|
1478
|
+
isReconnecting,
|
|
1479
|
+
reconnectFrozen,
|
|
1480
|
+
reconnectContent.length,
|
|
1481
|
+
runningActivityTool,
|
|
1482
|
+
],
|
|
1483
|
+
);
|
|
1448
1484
|
const lastBroadcastRunningRef = useRef(isRunning);
|
|
1449
1485
|
const tiptapRef = useRef<TiptapComposerHandle>(null);
|
|
1450
1486
|
// Stable ref to the "stop active run" action so addToQueue can abort
|
|
@@ -1700,11 +1736,14 @@ const AssistantChatInner = forwardRef<
|
|
|
1700
1736
|
|
|
1701
1737
|
reconnectRunIdRef.current = runId;
|
|
1702
1738
|
const afterSeq = resolveReconnectAfterSeq(threadId, runId);
|
|
1739
|
+
const storedActivityTool = getActiveRunActivityTool(threadId, runId);
|
|
1740
|
+
setRunningActivityTool(storedActivityTool);
|
|
1703
1741
|
setReconnectAfterSeq(afterSeq);
|
|
1704
1742
|
setActiveRun({
|
|
1705
1743
|
threadId,
|
|
1706
1744
|
runId,
|
|
1707
1745
|
lastSeq: afterSeq > 0 ? afterSeq - 1 : -1,
|
|
1746
|
+
...(storedActivityTool ? { activityTool: storedActivityTool } : {}),
|
|
1708
1747
|
});
|
|
1709
1748
|
setIsReconnecting(true);
|
|
1710
1749
|
setReconnectFrozen(false);
|
|
@@ -2407,7 +2446,10 @@ const AssistantChatInner = forwardRef<
|
|
|
2407
2446
|
const label =
|
|
2408
2447
|
typeof detail?.label === "string" ? detail.label.trim() : "";
|
|
2409
2448
|
if (!label) return;
|
|
2449
|
+
const tool = typeof detail?.tool === "string" ? detail.tool.trim() : "";
|
|
2410
2450
|
setIsAutoResuming(false);
|
|
2451
|
+
setRunningActivityTool(tool || null);
|
|
2452
|
+
updateActiveRunActivity(tool || null);
|
|
2411
2453
|
latestActivityLabelRef.current = label;
|
|
2412
2454
|
// Already past the delay → keep the visible label current.
|
|
2413
2455
|
if (activityLabelSurfacedRef.current) {
|
|
@@ -3549,6 +3591,13 @@ const AssistantChatInner = forwardRef<
|
|
|
3549
3591
|
reconnectContent.length > 0 && (
|
|
3550
3592
|
<ReconnectStreamMessage content={reconnectContent} />
|
|
3551
3593
|
)}
|
|
3594
|
+
{(isReconnecting || reconnectFrozen) &&
|
|
3595
|
+
reconnectAfterSeq > 0 &&
|
|
3596
|
+
reconnectActivityContent.length > 0 && (
|
|
3597
|
+
<ReconnectStreamMessage
|
|
3598
|
+
content={reconnectActivityContent}
|
|
3599
|
+
/>
|
|
3600
|
+
)}
|
|
3552
3601
|
{showRunningInUI && (
|
|
3553
3602
|
<RunningActivityStatus label={runningStatusLabel} />
|
|
3554
3603
|
)}
|
|
@@ -2,13 +2,20 @@ import { IconBrandGithub } from "@tabler/icons-react";
|
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
3
|
|
|
4
4
|
import { appPath } from "./api-path.js";
|
|
5
|
+
import { cn } from "./utils.js";
|
|
5
6
|
|
|
6
7
|
export interface PoweredByBadgeProps {
|
|
7
8
|
position?: "bottom-right" | "bottom-left";
|
|
9
|
+
/** Plain shows the logo only with no surrounding badge chrome. */
|
|
10
|
+
variant?: "badge" | "plain";
|
|
11
|
+
/** When true, positioning is handled by the parent container. */
|
|
12
|
+
embedded?: boolean;
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
export interface OpenSourceBadgeProps {
|
|
11
16
|
position?: "bottom-left" | "bottom-right";
|
|
17
|
+
/** When true, positioning is handled by the parent container. */
|
|
18
|
+
embedded?: boolean;
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
const containerStyle = (
|
|
@@ -51,6 +58,8 @@ const darkQuery = "(prefers-color-scheme: dark)";
|
|
|
51
58
|
*/
|
|
52
59
|
export function PoweredByBadge({
|
|
53
60
|
position = "bottom-right",
|
|
61
|
+
variant = "badge",
|
|
62
|
+
embedded = false,
|
|
54
63
|
}: PoweredByBadgeProps) {
|
|
55
64
|
// Allow hiding via env var
|
|
56
65
|
const hidden =
|
|
@@ -61,13 +70,14 @@ export function PoweredByBadge({
|
|
|
61
70
|
|
|
62
71
|
const logoOnLight = appPath("/agent-native-logo-light.svg");
|
|
63
72
|
const logoOnDark = appPath("/agent-native-logo-dark.svg");
|
|
73
|
+
const isPlain = variant === "plain";
|
|
64
74
|
|
|
65
75
|
return (
|
|
66
76
|
<>
|
|
67
77
|
<style>{`
|
|
68
78
|
.an-powered-logo {
|
|
69
79
|
display: block;
|
|
70
|
-
height: 14px;
|
|
80
|
+
height: ${isPlain ? "16.2px" : "14px"};
|
|
71
81
|
width: auto;
|
|
72
82
|
flex: none;
|
|
73
83
|
}
|
|
@@ -75,14 +85,25 @@ export function PoweredByBadge({
|
|
|
75
85
|
display: none;
|
|
76
86
|
}
|
|
77
87
|
@media (max-width: 640px) {
|
|
78
|
-
.an-powered-badge {
|
|
88
|
+
.an-powered-badge:not(.an-powered-badge-embedded) {
|
|
79
89
|
position: static !important;
|
|
80
90
|
margin: 0.75rem auto 0 !important;
|
|
81
91
|
width: max-content;
|
|
82
92
|
max-width: calc(100vw - 2rem);
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
|
-
.
|
|
95
|
+
.an-powered-badge-plain {
|
|
96
|
+
background: transparent !important;
|
|
97
|
+
border-color: transparent !important;
|
|
98
|
+
backdrop-filter: none !important;
|
|
99
|
+
-webkit-backdrop-filter: none !important;
|
|
100
|
+
padding: 0 !important;
|
|
101
|
+
opacity: 1 !important;
|
|
102
|
+
}
|
|
103
|
+
.an-powered-badge-plain:hover {
|
|
104
|
+
opacity: 0.82 !important;
|
|
105
|
+
}
|
|
106
|
+
.dark .an-powered-badge:not(.an-powered-badge-plain) {
|
|
86
107
|
background: rgba(255, 255, 255, 0.06) !important;
|
|
87
108
|
border-color: rgba(255, 255, 255, 0.08) !important;
|
|
88
109
|
color: rgba(215, 215, 215, 0.94) !important;
|
|
@@ -94,7 +115,7 @@ export function PoweredByBadge({
|
|
|
94
115
|
display: block;
|
|
95
116
|
}
|
|
96
117
|
@media ${darkQuery} {
|
|
97
|
-
.an-powered-badge {
|
|
118
|
+
.an-powered-badge:not(.an-powered-badge-plain) {
|
|
98
119
|
background: rgba(255, 255, 255, 0.06) !important;
|
|
99
120
|
border-color: rgba(255, 255, 255, 0.08) !important;
|
|
100
121
|
color: rgba(215, 215, 215, 0.94) !important;
|
|
@@ -106,7 +127,7 @@ export function PoweredByBadge({
|
|
|
106
127
|
display: block;
|
|
107
128
|
}
|
|
108
129
|
}
|
|
109
|
-
.light .an-powered-badge {
|
|
130
|
+
.light .an-powered-badge:not(.an-powered-badge-plain) {
|
|
110
131
|
background: rgba(0, 0, 0, 0.05) !important;
|
|
111
132
|
border-color: rgba(0, 0, 0, 0.06) !important;
|
|
112
133
|
color: rgba(95, 95, 95, 0.95) !important;
|
|
@@ -117,19 +138,19 @@ export function PoweredByBadge({
|
|
|
117
138
|
.light .an-powered-logo-dark {
|
|
118
139
|
display: none;
|
|
119
140
|
}
|
|
120
|
-
.an-powered-badge:hover {
|
|
141
|
+
.an-powered-badge:not(.an-powered-badge-plain):hover {
|
|
121
142
|
opacity: 1 !important;
|
|
122
143
|
color: rgba(70, 70, 70, 1) !important;
|
|
123
144
|
}
|
|
124
145
|
@media ${darkQuery} {
|
|
125
|
-
.an-powered-badge:hover {
|
|
146
|
+
.an-powered-badge:not(.an-powered-badge-plain):hover {
|
|
126
147
|
color: rgba(238, 238, 238, 1) !important;
|
|
127
148
|
}
|
|
128
149
|
}
|
|
129
|
-
.dark .an-powered-badge:hover {
|
|
150
|
+
.dark .an-powered-badge:not(.an-powered-badge-plain):hover {
|
|
130
151
|
color: rgba(238, 238, 238, 1) !important;
|
|
131
152
|
}
|
|
132
|
-
.light .an-powered-badge:hover {
|
|
153
|
+
.light .an-powered-badge:not(.an-powered-badge-plain):hover {
|
|
133
154
|
color: rgba(70, 70, 70, 1) !important;
|
|
134
155
|
}
|
|
135
156
|
`}</style>
|
|
@@ -137,11 +158,24 @@ export function PoweredByBadge({
|
|
|
137
158
|
href="https://agent-native.com"
|
|
138
159
|
target="_blank"
|
|
139
160
|
rel="noopener noreferrer"
|
|
140
|
-
className=
|
|
141
|
-
|
|
161
|
+
className={cn(
|
|
162
|
+
"an-powered-badge",
|
|
163
|
+
isPlain && "an-powered-badge-plain",
|
|
164
|
+
embedded && "an-powered-badge-embedded",
|
|
165
|
+
)}
|
|
166
|
+
style={
|
|
167
|
+
embedded
|
|
168
|
+
? {
|
|
169
|
+
display: "inline-flex",
|
|
170
|
+
alignItems: "center",
|
|
171
|
+
textDecoration: "none",
|
|
172
|
+
transition: "opacity 0.2s",
|
|
173
|
+
}
|
|
174
|
+
: containerStyle(position)
|
|
175
|
+
}
|
|
142
176
|
aria-label="Built with Agent Native"
|
|
143
177
|
>
|
|
144
|
-
<span>Built with</span>
|
|
178
|
+
{!isPlain && <span>Built with</span>}
|
|
145
179
|
<img
|
|
146
180
|
src={logoOnLight}
|
|
147
181
|
alt="Agent Native"
|
|
@@ -158,12 +192,13 @@ export function PoweredByBadge({
|
|
|
158
192
|
}
|
|
159
193
|
|
|
160
194
|
/**
|
|
161
|
-
* Small GitHub badge: "
|
|
195
|
+
* Small GitHub badge: "Free and open source"
|
|
162
196
|
*
|
|
163
197
|
* Intended to pair with PoweredByBadge on public pages.
|
|
164
198
|
*/
|
|
165
199
|
export function OpenSourceBadge({
|
|
166
200
|
position = "bottom-left",
|
|
201
|
+
embedded = false,
|
|
167
202
|
}: OpenSourceBadgeProps) {
|
|
168
203
|
const hidden =
|
|
169
204
|
(import.meta.env as Record<string, string | undefined>)
|
|
@@ -189,7 +224,7 @@ export function OpenSourceBadge({
|
|
|
189
224
|
opacity: 0.95 !important;
|
|
190
225
|
}
|
|
191
226
|
@media (max-width: 640px) {
|
|
192
|
-
.an-open-source-badge {
|
|
227
|
+
.an-open-source-badge:not(.an-open-source-badge-embedded) {
|
|
193
228
|
position: static !important;
|
|
194
229
|
margin: 1rem auto 0 !important;
|
|
195
230
|
width: max-content;
|
|
@@ -227,11 +262,29 @@ export function OpenSourceBadge({
|
|
|
227
262
|
href="https://github.com/BuilderIO/agent-native"
|
|
228
263
|
target="_blank"
|
|
229
264
|
rel="noopener noreferrer"
|
|
230
|
-
className=
|
|
231
|
-
|
|
265
|
+
className={cn(
|
|
266
|
+
"an-open-source-badge",
|
|
267
|
+
embedded && "an-open-source-badge-embedded",
|
|
268
|
+
)}
|
|
269
|
+
style={
|
|
270
|
+
embedded
|
|
271
|
+
? {
|
|
272
|
+
display: "flex",
|
|
273
|
+
alignItems: "center",
|
|
274
|
+
gap: 6,
|
|
275
|
+
fontSize: 12,
|
|
276
|
+
fontFamily:
|
|
277
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
278
|
+
fontWeight: 600,
|
|
279
|
+
lineHeight: 1,
|
|
280
|
+
textDecoration: "none",
|
|
281
|
+
transition: "opacity 0.2s, color 0.2s",
|
|
282
|
+
}
|
|
283
|
+
: containerStyle(position)
|
|
284
|
+
}
|
|
232
285
|
>
|
|
233
286
|
<IconBrandGithub aria-hidden="true" stroke={1.8} />
|
|
234
|
-
<span>
|
|
287
|
+
<span>Free and open source</span>
|
|
235
288
|
</a>
|
|
236
289
|
</>
|
|
237
290
|
);
|
|
@@ -4,6 +4,13 @@ export interface ActiveRunState {
|
|
|
4
4
|
threadId: string;
|
|
5
5
|
runId: string;
|
|
6
6
|
lastSeq: number;
|
|
7
|
+
activityTool?: string | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function normalizeActivityTool(toolName: unknown): string | null {
|
|
11
|
+
if (typeof toolName !== "string") return null;
|
|
12
|
+
const tool = toolName.trim();
|
|
13
|
+
return tool || null;
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
export function setActiveRun(state: ActiveRunState): void {
|
|
@@ -30,6 +37,29 @@ export function updateActiveRunSeq(seq: number): void {
|
|
|
30
37
|
}
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
export function updateActiveRunActivity(
|
|
41
|
+
toolName: string | null | undefined,
|
|
42
|
+
): void {
|
|
43
|
+
const state = getActiveRun();
|
|
44
|
+
if (!state) return;
|
|
45
|
+
const activityTool = normalizeActivityTool(toolName);
|
|
46
|
+
if (activityTool) {
|
|
47
|
+
setActiveRun({ ...state, activityTool });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const { activityTool: _activityTool, ...nextState } = state;
|
|
51
|
+
setActiveRun(nextState);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getActiveRunActivityTool(
|
|
55
|
+
threadId: string,
|
|
56
|
+
runId: string,
|
|
57
|
+
): string | null {
|
|
58
|
+
const stored = getActiveRun();
|
|
59
|
+
if (stored?.threadId !== threadId || stored.runId !== runId) return null;
|
|
60
|
+
return normalizeActivityTool(stored.activityTool);
|
|
61
|
+
}
|
|
62
|
+
|
|
33
63
|
export function clearActiveRun(): void {
|
|
34
64
|
try {
|
|
35
65
|
sessionStorage.removeItem(STORAGE_KEY);
|
|
@@ -944,6 +944,8 @@ function incrementalActionGuidance(tool: string): string | undefined {
|
|
|
944
944
|
case "generate-design":
|
|
945
945
|
case "update-design":
|
|
946
946
|
return 'if an existing design file or snapshot is already in history, especially after a Design variant pick, stop retrying `generate-design`: call `get-design-snapshot` for the selected file, then call `edit-design` once on that same `fileId` (`mode: "replace-file"` for a compact full-file replacement, or search/replace for smaller edits). Use `generate-design` only for a brand-new compact first file when no target file exists yet';
|
|
947
|
+
case "edit-design":
|
|
948
|
+
return "retry with a smaller `edit-design` payload: prefer a handful of exact search/replace edits against the already-snapshotted file, and avoid `replacementContent` for a huge full-file rewrite. If a selected variant needs expansion, upgrade the highest-value visible sections first, save once, and summarize any remaining refinements";
|
|
947
949
|
case "present-design-variants":
|
|
948
950
|
return 'call `present-design-variants` with concise labels, descriptions, accent colors, and feature bullets; omit large `content` HTML when needed so the action can render compact representative screens. After the user picks a direction, delete unchosen screens, snapshot the selected `fileId`, and refine that same file with `edit-design` (`mode: "replace-file"` for placeholder expansion). Do not call `generate-design` after the variant pick';
|
|
949
951
|
case "create-visual-plan":
|
|
@@ -980,7 +982,9 @@ function autoContinueMessage(signal: AgentAutoContinueSignal): string {
|
|
|
980
982
|
// toward a compact first version it can actually finish in a single run, then
|
|
981
983
|
// incremental refinements — never re-streaming the same oversized payload.
|
|
982
984
|
const cutoffPreparingAction =
|
|
983
|
-
signal.reason === "run_timeout" ||
|
|
985
|
+
signal.reason === "run_timeout" ||
|
|
986
|
+
signal.reason === "stream_ended" ||
|
|
987
|
+
signal.reason === "no_progress";
|
|
984
988
|
let actionInputNote = "";
|
|
985
989
|
if (cutoffPreparingAction && tool) {
|
|
986
990
|
const guidance = incrementalActionGuidance(tool);
|
|
@@ -9,8 +9,10 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|
|
9
9
|
import { useNavigate } from "react-router";
|
|
10
10
|
|
|
11
11
|
import { extensionPath } from "../../extensions/path.js";
|
|
12
|
+
import { THEME_VAR_NAMES } from "../../extensions/theme.js";
|
|
12
13
|
import { sendToAgentChat } from "../agent-chat.js";
|
|
13
14
|
import { agentNativePath } from "../api-path.js";
|
|
15
|
+
import { useAppearance } from "../appearance.js";
|
|
14
16
|
import {
|
|
15
17
|
Popover,
|
|
16
18
|
PopoverContent,
|
|
@@ -53,6 +55,22 @@ interface Extension {
|
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
// Read the host app's *actual* computed theme values for the shared token set
|
|
59
|
+
// (THEME_VAR_NAMES). The iframe ships with a generic baked palette
|
|
60
|
+
// (getThemeVars); syncing the live values keeps embedded extensions visually
|
|
61
|
+
// identical to the surrounding app even when a template overrides the default
|
|
62
|
+
// palette (e.g. analytics uses a neutral-gray dark theme, not near-black).
|
|
63
|
+
function readHostThemeVars(): Record<string, string> {
|
|
64
|
+
if (typeof document === "undefined") return {};
|
|
65
|
+
const computed = getComputedStyle(document.documentElement);
|
|
66
|
+
const vars: Record<string, string> = {};
|
|
67
|
+
for (const name of THEME_VAR_NAMES) {
|
|
68
|
+
const value = computed.getPropertyValue(name).trim();
|
|
69
|
+
if (value) vars[name] = value;
|
|
70
|
+
}
|
|
71
|
+
return vars;
|
|
72
|
+
}
|
|
73
|
+
|
|
56
74
|
function serializeChatValue(value: unknown): string | undefined {
|
|
57
75
|
if (value === undefined || value === null) return undefined;
|
|
58
76
|
if (typeof value === "string") return value;
|
|
@@ -112,7 +130,11 @@ export function EmbeddedExtension({
|
|
|
112
130
|
onReadyRef.current?.();
|
|
113
131
|
};
|
|
114
132
|
const [height, setHeight] = useState<number>(initialHeight);
|
|
115
|
-
const [isDark, setIsDark] = useState(
|
|
133
|
+
const [isDark, setIsDark] = useState(
|
|
134
|
+
() =>
|
|
135
|
+
typeof document !== "undefined" &&
|
|
136
|
+
document.documentElement.classList.contains("dark"),
|
|
137
|
+
);
|
|
116
138
|
// (audit H4) Mirror ExtensionViewer's role-aware gating; deny-by-default until
|
|
117
139
|
// the iframe's render binding announcement arrives.
|
|
118
140
|
const bridgeContextRef = useRef<BridgePolicyContext>({
|
|
@@ -200,11 +222,16 @@ export function EmbeddedExtension({
|
|
|
200
222
|
readyFiredRef.current = false;
|
|
201
223
|
}, [extensionId, extension?.updatedAt]);
|
|
202
224
|
|
|
225
|
+
const appearance = useAppearance();
|
|
226
|
+
|
|
203
227
|
useEffect(() => {
|
|
204
228
|
const win = iframeRef.current?.contentWindow;
|
|
205
229
|
if (!win) return;
|
|
206
|
-
win.postMessage(
|
|
207
|
-
|
|
230
|
+
win.postMessage(
|
|
231
|
+
{ type: "agent-native-theme-update", isDark, vars: readHostThemeVars() },
|
|
232
|
+
"*",
|
|
233
|
+
);
|
|
234
|
+
}, [isDark, appearance]);
|
|
208
235
|
|
|
209
236
|
// Forward slot context whenever it changes. The iframe's own load handler
|
|
210
237
|
// posts the initial value once it's ready; this effect handles updates.
|
|
@@ -372,6 +399,17 @@ export function EmbeddedExtension({
|
|
|
372
399
|
{ type: "agent-native-slot-context", context: context ?? {} },
|
|
373
400
|
"*",
|
|
374
401
|
);
|
|
402
|
+
// Re-assert theme once the iframe document is live. The src bakes in
|
|
403
|
+
// the initial dark state, but this covers the race where isDark
|
|
404
|
+
// settled before the iframe's message listener existed.
|
|
405
|
+
iframeRef.current?.contentWindow?.postMessage(
|
|
406
|
+
{
|
|
407
|
+
type: "agent-native-theme-update",
|
|
408
|
+
isDark,
|
|
409
|
+
vars: readHostThemeVars(),
|
|
410
|
+
},
|
|
411
|
+
"*",
|
|
412
|
+
);
|
|
375
413
|
// Fallback readiness signal in case the extension never reports a
|
|
376
414
|
// height (e.g. fixed-height content that skips auto-resize).
|
|
377
415
|
fireReady();
|