@agent-native/core 0.101.12 → 0.101.13
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 +8 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/create.ts +45 -8
- package/corpus/core/src/client/assistant-ui-recovery.tsx +9 -3
- package/corpus/core/src/client/chat/message-components.tsx +25 -2
- package/corpus/core/src/client/chat/tool-call-display.tsx +6 -9
- package/corpus/core/src/mcp/server.ts +10 -1
- package/corpus/core/src/server/agent-chat/framework-prompts.ts +0 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +2 -58
- package/corpus/core/src/server/prompts/framework-core-compact.ts +0 -1
- package/corpus/core/src/server/prompts/framework-core.ts +0 -30
- package/corpus/core/src/server/prompts/index.ts +1 -4
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +0 -14
- package/corpus/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +31 -7
- package/dist/cli/create.js.map +1 -1
- package/dist/client/assistant-ui-recovery.d.ts +2 -0
- package/dist/client/assistant-ui-recovery.d.ts.map +1 -1
- package/dist/client/assistant-ui-recovery.js +5 -2
- package/dist/client/assistant-ui-recovery.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +6 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +14 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +5 -8
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +10 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -1
- package/dist/server/agent-chat/framework-prompts.js +0 -3
- package/dist/server/agent-chat/framework-prompts.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +0 -22
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +2 -51
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/prompts/framework-core-compact.d.ts +0 -1
- package/dist/server/prompts/framework-core-compact.d.ts.map +1 -1
- package/dist/server/prompts/framework-core-compact.js +0 -1
- package/dist/server/prompts/framework-core-compact.js.map +1 -1
- package/dist/server/prompts/framework-core.d.ts +0 -9
- package/dist/server/prompts/framework-core.d.ts.map +1 -1
- package/dist/server/prompts/framework-core.js +0 -29
- package/dist/server/prompts/framework-core.js.map +1 -1
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.d.ts.map +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/index.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.101.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e503433: Keep CLI repository downloads asynchronous and challenge bare loopback MCP URLs for OAuth clients.
|
|
8
|
+
- e503433: Keep completed chat work disclosures collapsed and stable when submitting a later message.
|
|
9
|
+
- e503433: Remove the automatic first-session personalization questions from agent chat so new requests are handled directly.
|
|
10
|
+
|
|
3
11
|
## 0.101.12
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.101.
|
|
3
|
+
"version": "0.101.13",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFileSync } from "child_process";
|
|
1
|
+
import { execFile, execFileSync } from "child_process";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -1363,18 +1363,53 @@ function tarExtractArgs(
|
|
|
1363
1363
|
return ["xzf", tarPath, "--strip-components=1", ...excludes, "-C", destDir];
|
|
1364
1364
|
}
|
|
1365
1365
|
|
|
1366
|
-
function
|
|
1366
|
+
function execFileBuffer(
|
|
1367
|
+
command: string,
|
|
1368
|
+
args: string[],
|
|
1369
|
+
options: { maxBuffer: number },
|
|
1370
|
+
): Promise<Buffer> {
|
|
1371
|
+
return new Promise((resolve, reject) => {
|
|
1372
|
+
execFile(
|
|
1373
|
+
command,
|
|
1374
|
+
args,
|
|
1375
|
+
{ ...options, encoding: "buffer" },
|
|
1376
|
+
(error, stdout, stderr) => {
|
|
1377
|
+
if (error) {
|
|
1378
|
+
const detail = stderr?.toString().trim();
|
|
1379
|
+
if (detail) error.message = `${error.message}: ${detail}`;
|
|
1380
|
+
reject(error);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
resolve(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
1384
|
+
},
|
|
1385
|
+
);
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
async function downloadAndExtract(
|
|
1367
1390
|
url: string,
|
|
1368
1391
|
destDir: string,
|
|
1369
1392
|
options: { skipAgentSymlinks?: boolean } = {},
|
|
1370
|
-
): void {
|
|
1393
|
+
): Promise<void> {
|
|
1371
1394
|
fs.mkdirSync(destDir, { recursive: true });
|
|
1372
1395
|
// --fail-with-body so curl exits non-zero on HTTP 4xx/5xx instead of writing
|
|
1373
1396
|
// the error body (HTML/JSON) to disk where tar then fails with the opaque
|
|
1374
1397
|
// "Unrecognized archive format" message.
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1398
|
+
// Keep this asynchronous: a synchronous curl blocks the event loop, which
|
|
1399
|
+
// makes the create command's spinner look frozen during the GitHub fetch.
|
|
1400
|
+
const tarball = await execFileBuffer(
|
|
1401
|
+
"curl",
|
|
1402
|
+
[
|
|
1403
|
+
"--fail-with-body",
|
|
1404
|
+
"--connect-timeout",
|
|
1405
|
+
"10",
|
|
1406
|
+
"--max-time",
|
|
1407
|
+
"120",
|
|
1408
|
+
"-sL",
|
|
1409
|
+
url,
|
|
1410
|
+
],
|
|
1411
|
+
{ maxBuffer: 100 * 1024 * 1024 },
|
|
1412
|
+
);
|
|
1378
1413
|
const tarPath = path.join(destDir, ".download.tar.gz");
|
|
1379
1414
|
fs.writeFileSync(tarPath, tarball);
|
|
1380
1415
|
try {
|
|
@@ -1407,7 +1442,9 @@ async function downloadGitHubSubdir(
|
|
|
1407
1442
|
`.agent-native-tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
1408
1443
|
);
|
|
1409
1444
|
try {
|
|
1410
|
-
downloadAndExtract(tarUrl, tmpDir, {
|
|
1445
|
+
await downloadAndExtract(tarUrl, tmpDir, {
|
|
1446
|
+
skipAgentSymlinks: repo === REPO,
|
|
1447
|
+
});
|
|
1411
1448
|
const srcDir = path.join(tmpDir, subdir);
|
|
1412
1449
|
if (!fs.existsSync(srcDir)) {
|
|
1413
1450
|
throw new Error(
|
|
@@ -1435,7 +1472,7 @@ async function downloadGitHubRepo(
|
|
|
1435
1472
|
): Promise<void> {
|
|
1436
1473
|
validateRepoName(repo);
|
|
1437
1474
|
const tarUrl = `https://api.github.com/repos/${repo}/tarball/main`;
|
|
1438
|
-
downloadAndExtract(tarUrl, targetDir);
|
|
1475
|
+
await downloadAndExtract(tarUrl, targetDir);
|
|
1439
1476
|
}
|
|
1440
1477
|
|
|
1441
1478
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
@@ -38,6 +38,8 @@ export function isAssistantUiRecoverableRenderError(error: unknown): boolean {
|
|
|
38
38
|
|
|
39
39
|
type AssistantUiStaleIndexErrorBoundaryProps = {
|
|
40
40
|
resetKey: string;
|
|
41
|
+
/** Remount children when the recovery scope changes. */
|
|
42
|
+
remountOnResetKey?: boolean;
|
|
41
43
|
componentName?: string;
|
|
42
44
|
children: React.ReactNode;
|
|
43
45
|
};
|
|
@@ -173,10 +175,13 @@ export class AssistantUiStaleIndexErrorBoundary extends React.Component<
|
|
|
173
175
|
return null;
|
|
174
176
|
}
|
|
175
177
|
|
|
178
|
+
const fragmentKey =
|
|
179
|
+
this.props.remountOnResetKey === false
|
|
180
|
+
? String(this.state.retryToken)
|
|
181
|
+
: `${this.props.resetKey}:${this.state.retryToken}`;
|
|
182
|
+
|
|
176
183
|
return (
|
|
177
|
-
<React.Fragment key={
|
|
178
|
-
{this.props.children}
|
|
179
|
-
</React.Fragment>
|
|
184
|
+
<React.Fragment key={fragmentKey}>{this.props.children}</React.Fragment>
|
|
180
185
|
);
|
|
181
186
|
}
|
|
182
187
|
}
|
|
@@ -191,6 +196,7 @@ export function AssistantMessageListErrorBoundary({
|
|
|
191
196
|
return (
|
|
192
197
|
<AssistantUiStaleIndexErrorBoundary
|
|
193
198
|
resetKey={resetKey}
|
|
199
|
+
remountOnResetKey={false}
|
|
194
200
|
componentName="AssistantMessageList"
|
|
195
201
|
>
|
|
196
202
|
{children}
|
|
@@ -848,6 +848,25 @@ export function shouldShowAssistantMessageFooter({
|
|
|
848
848
|
return !chatRunning && statusIsTerminal;
|
|
849
849
|
}
|
|
850
850
|
|
|
851
|
+
export function shouldShowAssistantWorkSummary({
|
|
852
|
+
isLast,
|
|
853
|
+
isComplete,
|
|
854
|
+
hasCollapsibleWork,
|
|
855
|
+
hasUnresolvedTool,
|
|
856
|
+
}: {
|
|
857
|
+
isLast: boolean;
|
|
858
|
+
isComplete: boolean;
|
|
859
|
+
hasCollapsibleWork: boolean;
|
|
860
|
+
hasUnresolvedTool: boolean;
|
|
861
|
+
}): boolean {
|
|
862
|
+
if (!hasCollapsibleWork || hasUnresolvedTool) return false;
|
|
863
|
+
|
|
864
|
+
// Keep completed historical work wrapped while a later turn is running.
|
|
865
|
+
// Removing the wrapper exposes/remounts ReasoningCell and resets its
|
|
866
|
+
// disclosure state to the default-open value on every new submission.
|
|
867
|
+
return isComplete || !isLast;
|
|
868
|
+
}
|
|
869
|
+
|
|
851
870
|
function ReasoningMessagePart() {
|
|
852
871
|
const part = useMessagePartReasoning();
|
|
853
872
|
const partRuntime = useMessagePartRuntime();
|
|
@@ -1040,8 +1059,12 @@ export function AssistantMessage() {
|
|
|
1040
1059
|
{({ part, children }) => {
|
|
1041
1060
|
switch (part.type) {
|
|
1042
1061
|
case "group-work": {
|
|
1043
|
-
const showSummary =
|
|
1044
|
-
|
|
1062
|
+
const showSummary = shouldShowAssistantWorkSummary({
|
|
1063
|
+
isLast,
|
|
1064
|
+
isComplete,
|
|
1065
|
+
hasCollapsibleWork,
|
|
1066
|
+
hasUnresolvedTool,
|
|
1067
|
+
});
|
|
1045
1068
|
if (!showSummary) return <>{children}</>;
|
|
1046
1069
|
return (
|
|
1047
1070
|
<WorkedForSummary
|
|
@@ -1088,20 +1088,17 @@ export function WorkedForSummary({
|
|
|
1088
1088
|
children,
|
|
1089
1089
|
}: {
|
|
1090
1090
|
durationMs?: number | null;
|
|
1091
|
-
/** When true,
|
|
1091
|
+
/** When true, close the summary after a run has completed. */
|
|
1092
1092
|
autoCollapse?: boolean;
|
|
1093
1093
|
children: React.ReactNode;
|
|
1094
1094
|
}) {
|
|
1095
|
-
|
|
1096
|
-
|
|
1095
|
+
// Start closed so a remounted completed message never flashes its work
|
|
1096
|
+
// details open while auto-collapse settles. If the summary was already
|
|
1097
|
+
// open when autoCollapse changes, AnimatedCollapse still animates it shut.
|
|
1098
|
+
const [open, setOpen] = useState(false);
|
|
1097
1099
|
|
|
1098
1100
|
useEffect(() => {
|
|
1099
|
-
if (
|
|
1100
|
-
didAutoCollapseRef.current = true;
|
|
1101
|
-
const frame = requestAnimationFrame(() => {
|
|
1102
|
-
setOpen(false);
|
|
1103
|
-
});
|
|
1104
|
-
return () => cancelAnimationFrame(frame);
|
|
1101
|
+
if (autoCollapse) setOpen(false);
|
|
1105
1102
|
}, [autoCollapse]);
|
|
1106
1103
|
|
|
1107
1104
|
const label =
|
|
@@ -310,9 +310,18 @@ export async function handleMcpRequest(
|
|
|
310
310
|
// must fail closed rather than trust a spoofable owner-email header that
|
|
311
311
|
// `fullSurface` would otherwise escalate to the full mutating surface.
|
|
312
312
|
const requestMeta = deriveRequestMeta(event);
|
|
313
|
+
const hasLocalOwnerHint = Boolean(ownerEmailHeader?.trim());
|
|
313
314
|
const authResult = await verifyAuth(authHeader, ownerEmailHeader, {
|
|
315
|
+
// A bare localhost URL is still a protected MCP resource. This lets
|
|
316
|
+
// OAuth-native hosts (Kiro, Claude Code, etc.) receive the standard 401
|
|
317
|
+
// challenge and open browser approval instead of silently getting the
|
|
318
|
+
// sparse anonymous dev surface. The stdio proxy remains zero-config for
|
|
319
|
+
// local installs because it forwards an owner hint; an explicit opt-in is
|
|
320
|
+
// available for local diagnostics.
|
|
314
321
|
allowDevOpen:
|
|
315
|
-
isLoopbackRequest(event) &&
|
|
322
|
+
isLoopbackRequest(event) &&
|
|
323
|
+
isLoopbackOrigin(requestMeta.origin) &&
|
|
324
|
+
(hasLocalOwnerHint || process.env.AGENT_NATIVE_MCP_DEV_OPEN === "1"),
|
|
316
325
|
resourceUrl: getMcpOAuthAudiences(event),
|
|
317
326
|
});
|
|
318
327
|
if (!authResult.authed) {
|
|
@@ -45,9 +45,6 @@ export function buildFrameworkPrompts(
|
|
|
45
45
|
PROD_FRAMEWORK_PROMPT_COMPACT: string;
|
|
46
46
|
DEV_FRAMEWORK_PROMPT_COMPACT: string;
|
|
47
47
|
} {
|
|
48
|
-
// Note: FIRST_SESSION_PERSONALIZATION is NOT appended here — it is injected
|
|
49
|
-
// at per-request prompt-assembly time only for new threads (no prior messages).
|
|
50
|
-
// This prevents the ~1.5KB block from appearing on every request forever.
|
|
51
48
|
const FRAMEWORK_CORE = buildFrameworkCore(examples, options);
|
|
52
49
|
const FRAMEWORK_CORE_COMPACT = buildFrameworkCoreCompact(examples, options);
|
|
53
50
|
const extensionToolsEnabled = options?.extensionTools !== false;
|
|
@@ -86,7 +86,6 @@ import type {
|
|
|
86
86
|
MentionProvider,
|
|
87
87
|
} from "../agent/types.js";
|
|
88
88
|
import { readAppStateForCurrentTab } from "../application-state/script-helpers.js";
|
|
89
|
-
import { appStateGet } from "../application-state/store.js";
|
|
90
89
|
import {
|
|
91
90
|
createThread,
|
|
92
91
|
forkThread,
|
|
@@ -167,10 +166,7 @@ import {
|
|
|
167
166
|
} from "./framework-request-handler.js";
|
|
168
167
|
import { getOrigin } from "./google-oauth.js";
|
|
169
168
|
import { readBody } from "./h3-helpers.js";
|
|
170
|
-
import {
|
|
171
|
-
FIRST_SESSION_PERSONALIZATION,
|
|
172
|
-
getModelFamilyOverlay,
|
|
173
|
-
} from "./prompts/index.js";
|
|
169
|
+
import { getModelFamilyOverlay } from "./prompts/index.js";
|
|
174
170
|
import { mountRealtimeVoiceRoutes } from "./realtime-voice.js";
|
|
175
171
|
import {
|
|
176
172
|
runWithRequestContext,
|
|
@@ -283,41 +279,6 @@ export function buildLeanRunPolicyPrompt(
|
|
|
283
279
|
return codeEditingSurfaceRestriction + prodCodeExecPromptNote;
|
|
284
280
|
}
|
|
285
281
|
|
|
286
|
-
/**
|
|
287
|
-
* Returns whether `owner` has already finished (or explicitly skipped) the
|
|
288
|
-
* First-Session Personalization flow, via the owner-scoped
|
|
289
|
-
* `application_state` "personalization" flag the agent itself writes
|
|
290
|
-
* (`writeAppState("personalization", { done: true })` — see
|
|
291
|
-
* FIRST_SESSION_PERSONALIZATION in prompts/framework-core.ts).
|
|
292
|
-
*
|
|
293
|
-
* This used to be gated on "does this thread have prior messages", which
|
|
294
|
-
* flips false the instant a second request comes in for the SAME thread —
|
|
295
|
-
* making turn 2's system prompt diverge from turn 1's and invalidating the
|
|
296
|
-
* prompt-cache prefix on every thread's second request. The flow itself
|
|
297
|
-
* spans two turns (turn 1 asks the personalization questions and waits;
|
|
298
|
-
* turn 2 answers them and only then writes the "done" flag), so this flag
|
|
299
|
-
* is still false when BOTH turns' system prompts are assembled — turn 1
|
|
300
|
-
* and turn 2 come out byte-identical. It only flips once the flow
|
|
301
|
-
* completes, and it never flips back, so every later turn (and every
|
|
302
|
-
* later thread the same owner creates) stays consistent from then on. As
|
|
303
|
-
* a bonus, it also fixes a latent waste: the old gate re-included the
|
|
304
|
-
* ~1.5KB block on turn 1 of every new thread a user ever created, even
|
|
305
|
-
* long after they'd completed personalization once.
|
|
306
|
-
*/
|
|
307
|
-
export async function hasCompletedFirstSessionPersonalization(
|
|
308
|
-
owner: string,
|
|
309
|
-
): Promise<boolean> {
|
|
310
|
-
try {
|
|
311
|
-
const state = await appStateGet(owner, "personalization");
|
|
312
|
-
return state?.done === true;
|
|
313
|
-
} catch {
|
|
314
|
-
// Fail open to "not done" — same default as a brand-new user (block
|
|
315
|
-
// shown) rather than silently skipping personalization because of a
|
|
316
|
-
// transient appstate read error.
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
282
|
/**
|
|
322
283
|
* In-memory rate-limit tracker for `/generate-title`. Keyed by user email,
|
|
323
284
|
* value is recent invocation timestamps within the rolling window. Stale
|
|
@@ -2650,14 +2611,6 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2650
2611
|
)
|
|
2651
2612
|
? APP_RENDERED_CHAT_NO_DIRECT_CODE_PROMPT
|
|
2652
2613
|
: "";
|
|
2653
|
-
// Personalization block: included until this owner has finished (or
|
|
2654
|
-
// skipped) the flow — see hasCompletedFirstSessionPersonalization
|
|
2655
|
-
// for why this is gated on the owner-scoped appstate flag rather
|
|
2656
|
-
// than "is this a new thread" (keeps turn 1 and turn 2 identical).
|
|
2657
|
-
const personalizationBlock =
|
|
2658
|
-
(await hasCompletedFirstSessionPersonalization(owner))
|
|
2659
|
-
? ""
|
|
2660
|
-
: FIRST_SESSION_PERSONALIZATION;
|
|
2661
2614
|
// Per-model overlay: nudge GPT/Gemini engines toward our behavioral norms.
|
|
2662
2615
|
const modelOverlay = resolveModelOverlay();
|
|
2663
2616
|
// Stable-first ordering: base prompt / schema / extra come before
|
|
@@ -2712,13 +2665,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2712
2665
|
modelOverlay,
|
|
2713
2666
|
runtimeContext,
|
|
2714
2667
|
additionalFramework:
|
|
2715
|
-
|
|
2716
|
-
codeEditingSurfaceRestriction +
|
|
2717
|
-
prodCodeExecPromptNote,
|
|
2668
|
+
codeEditingSurfaceRestriction + prodCodeExecPromptNote,
|
|
2718
2669
|
});
|
|
2719
2670
|
return setSystemPromptOnContext(
|
|
2720
2671
|
basePrompt +
|
|
2721
|
-
personalizationBlock +
|
|
2722
2672
|
resources +
|
|
2723
2673
|
schemaBlock +
|
|
2724
2674
|
codeEditingSurfaceRestriction +
|
|
@@ -2940,10 +2890,6 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2940
2890
|
systemPrompt: async (event: any) => {
|
|
2941
2891
|
const { owner, extra } = await prepareRun(event);
|
|
2942
2892
|
const runtimeContext = runtimeContextForEvent(event);
|
|
2943
|
-
const personalizationBlock =
|
|
2944
|
-
(await hasCompletedFirstSessionPersonalization(owner))
|
|
2945
|
-
? ""
|
|
2946
|
-
: FIRST_SESSION_PERSONALIZATION;
|
|
2947
2893
|
const modelOverlay = resolveModelOverlay();
|
|
2948
2894
|
// Stable-first ordering: runtimeContext (day-granular) is
|
|
2949
2895
|
// appended LAST so a day rollover invalidates as little of the
|
|
@@ -2989,11 +2935,9 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2989
2935
|
extra,
|
|
2990
2936
|
modelOverlay,
|
|
2991
2937
|
runtimeContext,
|
|
2992
|
-
additionalFramework: personalizationBlock,
|
|
2993
2938
|
});
|
|
2994
2939
|
return setSystemPromptOnContext(
|
|
2995
2940
|
devPrompt +
|
|
2996
|
-
personalizationBlock +
|
|
2997
2941
|
resources +
|
|
2998
2942
|
schemaBlock +
|
|
2999
2943
|
extra +
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* - Verbose "Extended Capabilities" section (agent uses get-framework-context)
|
|
8
8
|
* - Detailed "Parallel Tool Calls" prose (replaced with one-liner)
|
|
9
9
|
* - Detailed "Resources" section (agent uses resources tool)
|
|
10
|
-
* - "First-Session Personalization" (gated externally — see buildSystemPrompt)
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
import {
|
|
@@ -141,33 +141,3 @@ Each of these has a one-line pointer here and a full doc you can pull on demand
|
|
|
141
141
|
- **Structured memory** — persist knowledge across sessions with \`save-memory\` / \`delete-memory\`; save proactively when you learn preferences, corrections, or project context. Detailed instructions: call \`get-framework-context\` with key \`memory\`.
|
|
142
142
|
`;
|
|
143
143
|
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Build the First-Session Personalization block.
|
|
147
|
-
* Gated by caller: only include when the session has no prior messages
|
|
148
|
-
* (cheapest reliable signal that personalization hasn't run yet).
|
|
149
|
-
* Recording happens via writeAppState("personalization", { done: true })
|
|
150
|
-
* so the block is omitted from all subsequent requests once the agent
|
|
151
|
-
* completes the flow.
|
|
152
|
-
*/
|
|
153
|
-
export const FIRST_SESSION_PERSONALIZATION = `
|
|
154
|
-
### First-Session Personalization
|
|
155
|
-
|
|
156
|
-
On the user's very first interaction in this app, before answering their actual request, briefly personalize the workspace.
|
|
157
|
-
|
|
158
|
-
Check the application_state key \`personalization\` via \`readAppState("personalization")\`:
|
|
159
|
-
- If it returns null (or has no \`done: true\`), this is the first session — run the flow below.
|
|
160
|
-
- If \`done: true\` is set, skip the flow and answer normally.
|
|
161
|
-
|
|
162
|
-
**The flow (keep it to one short message, then wait for their answer before continuing):**
|
|
163
|
-
|
|
164
|
-
1. Greet briefly in one sentence.
|
|
165
|
-
2. Ask **two** yes/no questions inline, on separate lines:
|
|
166
|
-
- A theme question: _"Want me to pick a color theme for your workspace? I have a few presets — say a name or just 'yes' for my pick."_ Available presets: \`warm\`, \`ocean\`, \`forest\`, \`rose\`, \`slate\` (call \`change-appearance\` with one of these; or \`default\` to clear). When the user says yes without a name, pick one preset that fits this template's tone.
|
|
167
|
-
- A template-specific question that the template's AGENTS.md / CLAUDE.md documents (e.g. for calendar: _"Want me to color-code meetings by attendee or by category?"_; for mail: _"Want me to surface emails that look like they need a reply at the top?"_). If the template doesn't suggest a question, ask one generic preference question (e.g. _"Do you prefer a denser layout or roomy spacing?"_).
|
|
168
|
-
3. After they answer (or decline), call \`change-appearance\` if appropriate, do whatever the second answer implies (e.g. set a calendar visual preference), and then write \`application_state.personalization\` = \`{ "done": true }\` via \`writeAppState\` so this flow doesn't run again.
|
|
169
|
-
|
|
170
|
-
If the user's first message is clearly already on-task (e.g. "what's on my calendar today?"), answer it first — but still surface ONE line at the end like _"By the way, want me to set a theme for your workspace? Try \`change-appearance warm\` or just ask."_ — then mark personalization done so the offer never repeats.
|
|
171
|
-
|
|
172
|
-
Do NOT block on this flow. If the user ignores it, just proceed; never re-ask the personalization questions in later sessions.
|
|
173
|
-
`;
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
* agent-chat-plugin.ts has a single clean import.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export {
|
|
7
|
-
buildFrameworkCore,
|
|
8
|
-
FIRST_SESSION_PERSONALIZATION,
|
|
9
|
-
} from "./framework-core.js";
|
|
6
|
+
export { buildFrameworkCore } from "./framework-core.js";
|
|
10
7
|
export { buildFrameworkCoreCompact } from "./framework-core-compact.js";
|
|
11
8
|
export {
|
|
12
9
|
sharedRule8,
|
|
@@ -9,10 +9,8 @@ import {
|
|
|
9
9
|
import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
|
|
10
10
|
import { OrgSwitcher } from "@agent-native/core/client/org";
|
|
11
11
|
import {
|
|
12
|
-
IconActivity,
|
|
13
12
|
IconArchive,
|
|
14
13
|
IconBrain,
|
|
15
|
-
IconDatabase,
|
|
16
14
|
IconDots,
|
|
17
15
|
IconEdit,
|
|
18
16
|
IconLayoutSidebarLeftCollapse,
|
|
@@ -48,18 +46,6 @@ const navItems = [
|
|
|
48
46
|
href: "/",
|
|
49
47
|
view: "chat",
|
|
50
48
|
},
|
|
51
|
-
{
|
|
52
|
-
icon: IconActivity,
|
|
53
|
-
labelKey: "navigation.observability",
|
|
54
|
-
href: "/observability",
|
|
55
|
-
view: "observability",
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
icon: IconDatabase,
|
|
59
|
-
labelKey: "navigation.database",
|
|
60
|
-
href: "/database",
|
|
61
|
-
view: "database",
|
|
62
|
-
},
|
|
63
49
|
{
|
|
64
50
|
icon: IconBrain,
|
|
65
51
|
labelKey: "settings.agentTitle",
|
package/dist/cli/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/cli/create.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAkB,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AA8BvE;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AA6BD,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,gBAAgB,GACtB,OAAO,CAAC,IAAI,CAAC,CAwEf;AA2OD,iBAAS,oCAAoC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAa1E;AAiBD,iBAAe,qBAAqB,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAiDD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,gBAAgB,GACtB,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAoLD;;;;;GAKG;AACH,iBAAe,mBAAmB,CAChC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAmDD;;;;GAIG;AACH,iBAAe,wBAAwB,CACrC,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAkFf;AAED;;;GAGG;AACH,iBAAS,qBAAqB,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CA4HN;AAmLD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,GACf;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkB7D;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,yCAAyC;AACzC,OAAO,EACL,qBAAqB,IAAI,sBAAsB,EAC/C,mBAAmB,IAAI,oBAAoB,EAC3C,wBAAwB,IAAI,yBAAyB,EACrD,qBAAqB,IAAI,sBAAsB,EAC/C,WAAW,IAAI,YAAY,EAC3B,kBAAkB,IAAI,mBAAmB,EACzC,eAAe,IAAI,gBAAgB,EACnC,kBAAkB,IAAI,mBAAmB,EACzC,wBAAwB,IAAI,yBAAyB,EACrD,4BAA4B,IAAI,6BAA6B,EAC7D,2BAA2B,IAAI,4BAA4B,EAC3D,oBAAoB,IAAI,qBAAqB,EAC7C,8BAA8B,IAAI,+BAA+B,EACjE,oCAAoC,IAAI,qCAAqC,EAC7E,uBAAuB,IAAI,wBAAwB,EACnD,cAAc,IAAI,eAAe,GAClC,CAAC;AAcF,iBAAS,cAAc,CACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5C,MAAM,EAAE,CAQV;
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/cli/create.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/create.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFileSync } from "child_process";
|
|
1
|
+
import { execFile, execFileSync } from "child_process";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -1102,14 +1102,36 @@ function tarExtractArgs(tarPath, destDir, options = {}) {
|
|
|
1102
1102
|
: [];
|
|
1103
1103
|
return ["xzf", tarPath, "--strip-components=1", ...excludes, "-C", destDir];
|
|
1104
1104
|
}
|
|
1105
|
-
function
|
|
1105
|
+
function execFileBuffer(command, args, options) {
|
|
1106
|
+
return new Promise((resolve, reject) => {
|
|
1107
|
+
execFile(command, args, { ...options, encoding: "buffer" }, (error, stdout, stderr) => {
|
|
1108
|
+
if (error) {
|
|
1109
|
+
const detail = stderr?.toString().trim();
|
|
1110
|
+
if (detail)
|
|
1111
|
+
error.message = `${error.message}: ${detail}`;
|
|
1112
|
+
reject(error);
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
resolve(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
|
|
1116
|
+
});
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
async function downloadAndExtract(url, destDir, options = {}) {
|
|
1106
1120
|
fs.mkdirSync(destDir, { recursive: true });
|
|
1107
1121
|
// --fail-with-body so curl exits non-zero on HTTP 4xx/5xx instead of writing
|
|
1108
1122
|
// the error body (HTML/JSON) to disk where tar then fails with the opaque
|
|
1109
1123
|
// "Unrecognized archive format" message.
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1124
|
+
// Keep this asynchronous: a synchronous curl blocks the event loop, which
|
|
1125
|
+
// makes the create command's spinner look frozen during the GitHub fetch.
|
|
1126
|
+
const tarball = await execFileBuffer("curl", [
|
|
1127
|
+
"--fail-with-body",
|
|
1128
|
+
"--connect-timeout",
|
|
1129
|
+
"10",
|
|
1130
|
+
"--max-time",
|
|
1131
|
+
"120",
|
|
1132
|
+
"-sL",
|
|
1133
|
+
url,
|
|
1134
|
+
], { maxBuffer: 100 * 1024 * 1024 });
|
|
1113
1135
|
const tarPath = path.join(destDir, ".download.tar.gz");
|
|
1114
1136
|
fs.writeFileSync(tarPath, tarball);
|
|
1115
1137
|
try {
|
|
@@ -1132,7 +1154,9 @@ async function downloadGitHubSubdir(repo, subdir, targetDir) {
|
|
|
1132
1154
|
const tarUrl = `https://api.github.com/repos/${repo}/tarball/${encodeURIComponent(ref)}`;
|
|
1133
1155
|
const tmpDir = path.join(targetDir, "..", `.agent-native-tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
1134
1156
|
try {
|
|
1135
|
-
downloadAndExtract(tarUrl, tmpDir, {
|
|
1157
|
+
await downloadAndExtract(tarUrl, tmpDir, {
|
|
1158
|
+
skipAgentSymlinks: repo === REPO,
|
|
1159
|
+
});
|
|
1136
1160
|
const srcDir = path.join(tmpDir, subdir);
|
|
1137
1161
|
if (!fs.existsSync(srcDir)) {
|
|
1138
1162
|
throw new Error(`Template directory "${subdir}" not found at ref "${ref}".`);
|
|
@@ -1152,7 +1176,7 @@ async function downloadGitHubSubdir(repo, subdir, targetDir) {
|
|
|
1152
1176
|
async function downloadGitHubRepo(repo, targetDir) {
|
|
1153
1177
|
validateRepoName(repo);
|
|
1154
1178
|
const tarUrl = `https://api.github.com/repos/${repo}/tarball/main`;
|
|
1155
|
-
downloadAndExtract(tarUrl, targetDir);
|
|
1179
|
+
await downloadAndExtract(tarUrl, targetDir);
|
|
1156
1180
|
}
|
|
1157
1181
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
1158
1182
|
* Text / filesystem helpers
|