@agent-native/core 0.144.3 → 0.145.1
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/templates/clips/changelog/2026-08-06-desktop-full-screen-recordings-now-normalize-microphone-leve.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +185 -69
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +47 -4
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/dist/agent/production-agent.d.ts +6 -0
- package/dist/agent/run-manager.d.ts +44 -1
- package/dist/agent/run-manager.js +70 -8
- package/dist/chat-threads/store.js +6 -4
- package/dist/client/use-db-sync.js +9 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/ddl-guard.d.ts +8 -0
- package/dist/db/ddl-guard.js +148 -0
- package/dist/deploy/build.d.ts +36 -0
- package/dist/deploy/build.js +78 -5
- package/dist/framework-tools.d.ts +126 -0
- package/dist/framework-tools.js +114 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/org/accept-pending.js +2 -2
- package/dist/org/auth-policy.js +4 -0
- package/dist/org/auto-join-domain.d.ts +9 -0
- package/dist/org/auto-join-domain.js +53 -4
- package/dist/org/context.js +12 -3
- package/dist/org/handlers.js +17 -5
- package/dist/org/request-org-cache.d.ts +24 -2
- package/dist/org/request-org-cache.js +57 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +6 -6
- package/dist/resources/store.d.ts +1 -1
- package/dist/resources/store.js +96 -7
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-discovery.d.ts +27 -0
- package/dist/server/action-discovery.js +89 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +11 -0
- package/dist/server/agent-chat/action-filters-a2a.js +17 -1
- package/dist/server/agent-chat/framework-prompts.d.ts +2 -0
- package/dist/server/agent-chat/plugin-options.d.ts +30 -0
- package/dist/server/agent-chat/prompt-resources.d.ts +4 -1
- package/dist/server/agent-chat/prompt-resources.js +8 -2
- package/dist/server/agent-chat-plugin.js +138 -75
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +3 -0
- package/dist/server/auth.js +22 -1
- package/dist/server/collab-plugin.js +10 -4
- package/dist/server/core-routes-plugin.js +3 -0
- package/dist/server/prompts/framework-core-compact.d.ts +5 -0
- package/dist/server/prompts/framework-core-compact.js +28 -12
- package/dist/server/prompts/framework-core.d.ts +5 -0
- package/dist/server/prompts/framework-core.js +33 -16
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/shared-rules.d.ts +12 -4
- package/dist/server/prompts/shared-rules.js +14 -4
- package/dist/server/session-email-cache.d.ts +14 -0
- package/dist/server/session-email-cache.js +48 -0
- package/dist/server/sweep-runtime.d.ts +22 -0
- package/dist/server/sweep-runtime.js +28 -0
- package/dist/settings/store.js +63 -7
- package/dist/shared/ttl-cache.d.ts +59 -0
- package/dist/shared/ttl-cache.js +43 -0
- package/dist/sharing/actions/list-resource-shares.d.ts +3 -3
- package/dist/sharing/actions/list-resource-shares.js +4 -1
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -3
- package/dist/triggers/condition-evaluator.js +11 -27
- package/docs/content/deployment.mdx +95 -13
- package/docs/content/environment-variables.mdx +5 -0
- package/docs/content/key-concepts.mdx +13 -6
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -3
|
@@ -75,7 +75,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
|
|
78
|
+
message?: undefined;
|
|
79
79
|
deleted?: undefined;
|
|
80
80
|
found?: undefined;
|
|
81
81
|
providers: {
|
|
@@ -90,19 +90,20 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
90
90
|
count: number;
|
|
91
91
|
provider?: undefined;
|
|
92
92
|
registered?: undefined;
|
|
93
|
+
id?: undefined;
|
|
93
94
|
label?: undefined;
|
|
94
|
-
message?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
|
|
96
|
+
message?: undefined;
|
|
97
97
|
deleted?: undefined;
|
|
98
98
|
providers?: undefined;
|
|
99
99
|
count?: undefined;
|
|
100
100
|
found: boolean;
|
|
101
101
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
102
102
|
registered?: undefined;
|
|
103
|
+
id?: undefined;
|
|
103
104
|
label?: undefined;
|
|
104
|
-
message?: undefined;
|
|
105
105
|
} | {
|
|
106
|
+
message?: undefined;
|
|
106
107
|
deleted?: undefined;
|
|
107
108
|
providers?: undefined;
|
|
108
109
|
count?: undefined;
|
|
@@ -111,8 +112,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
111
112
|
id: string;
|
|
112
113
|
registered?: undefined;
|
|
113
114
|
label?: undefined;
|
|
114
|
-
message?: undefined;
|
|
115
115
|
} | {
|
|
116
|
+
message?: undefined;
|
|
116
117
|
found?: undefined;
|
|
117
118
|
providers?: undefined;
|
|
118
119
|
count?: undefined;
|
|
@@ -121,7 +122,6 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
121
122
|
id: string;
|
|
122
123
|
registered?: undefined;
|
|
123
124
|
label?: undefined;
|
|
124
|
-
message?: undefined;
|
|
125
125
|
} | {
|
|
126
126
|
deleted?: undefined;
|
|
127
127
|
found?: undefined;
|
|
@@ -311,9 +311,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
+
deleted?: undefined;
|
|
314
315
|
id?: undefined;
|
|
315
316
|
provider?: undefined;
|
|
316
|
-
deleted?: undefined;
|
|
317
317
|
found?: undefined;
|
|
318
318
|
providers: {
|
|
319
319
|
id: string;
|
|
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
329
329
|
label?: undefined;
|
|
330
330
|
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
-
id?: undefined;
|
|
333
332
|
deleted?: undefined;
|
|
334
333
|
count?: undefined;
|
|
334
|
+
id?: undefined;
|
|
335
335
|
providers?: undefined;
|
|
336
336
|
found: boolean;
|
|
337
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
@@ -339,9 +339,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
339
339
|
label?: undefined;
|
|
340
340
|
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
-
provider?: undefined;
|
|
343
342
|
deleted?: undefined;
|
|
344
343
|
count?: undefined;
|
|
344
|
+
provider?: undefined;
|
|
345
345
|
providers?: undefined;
|
|
346
346
|
found: boolean;
|
|
347
347
|
id: string;
|
|
@@ -349,9 +349,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
349
349
|
label?: undefined;
|
|
350
350
|
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
+
count?: undefined;
|
|
352
353
|
provider?: undefined;
|
|
353
354
|
found?: undefined;
|
|
354
|
-
count?: undefined;
|
|
355
355
|
providers?: undefined;
|
|
356
356
|
deleted: boolean;
|
|
357
357
|
id: string;
|
|
@@ -359,10 +359,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
359
359
|
label?: undefined;
|
|
360
360
|
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
provider?: undefined;
|
|
363
362
|
deleted?: undefined;
|
|
364
|
-
found?: undefined;
|
|
365
363
|
count?: undefined;
|
|
364
|
+
provider?: undefined;
|
|
365
|
+
found?: undefined;
|
|
366
366
|
providers?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isLocalWorkspaceResourceId } from "../local-artifacts/index.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type StoreWriteOptions } from "../settings/store.js";
|
|
3
3
|
export declare const SHARED_OWNER = "__shared__";
|
|
4
4
|
export declare const WORKSPACE_OWNER = "__workspace__";
|
|
5
5
|
/**
|
package/dist/resources/store.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ensureColumnExists, ensureIndexExists, ensureTableExists, } from "../db
|
|
|
4
4
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
5
5
|
import { canUseLocalWorkspaceResourcePath, deleteLocalWorkspaceResource, isLocalWorkspaceResourceId, isLocalWorkspaceResourcesEnabled, listLocalWorkspaceResources, localWorkspaceResourcePathFromId, readLocalWorkspaceResource, writeLocalWorkspaceResource, } from "../local-artifacts/index.js";
|
|
6
6
|
import { getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
|
|
7
|
+
import { getSetting, putSetting, } from "../settings/store.js";
|
|
7
8
|
import { emitResourceChange, emitResourceDelete } from "./emitter.js";
|
|
8
9
|
export const SHARED_OWNER = "__shared__";
|
|
9
10
|
export const WORKSPACE_OWNER = "__workspace__";
|
|
@@ -570,14 +571,34 @@ async function grantedWorkspaceResourceByPath(path, options) {
|
|
|
570
571
|
return null;
|
|
571
572
|
}
|
|
572
573
|
}
|
|
573
|
-
|
|
574
|
+
/**
|
|
575
|
+
* Expire agent scratch resources, WITHOUT blocking the read that triggered it.
|
|
576
|
+
*
|
|
577
|
+
* This is garbage collection, not part of any read's answer: a caller asking for
|
|
578
|
+
* one resource does not need yesterday's expired scratch rows gone first. Awaiting
|
|
579
|
+
* it made every read path issue a `DELETE` before its own `SELECT` — double the
|
|
580
|
+
* round trips, unservable by a replica, taking row locks inside a request a user
|
|
581
|
+
* is waiting on, and (since nothing caught it) able to fail the read outright.
|
|
582
|
+
*
|
|
583
|
+
* The throttle is a module-scope timestamp, so it starts at 0 in a fresh isolate
|
|
584
|
+
* and the first resource read after every cold start still triggers one sweep.
|
|
585
|
+
* That is why the index below exists, and why this must not be awaited.
|
|
586
|
+
*/
|
|
587
|
+
function scheduleExpiredAgentScratchCleanup(client) {
|
|
574
588
|
const now = Date.now();
|
|
575
589
|
if (now - _lastScratchCleanupAt < SCRATCH_CLEANUP_INTERVAL_MS)
|
|
576
590
|
return;
|
|
577
591
|
_lastScratchCleanupAt = now;
|
|
578
|
-
|
|
592
|
+
void client
|
|
593
|
+
.execute({
|
|
579
594
|
sql: `DELETE FROM resources WHERE visibility = ? AND expires_at IS NOT NULL AND expires_at <= ?`,
|
|
580
595
|
args: ["agent_scratch", now],
|
|
596
|
+
})
|
|
597
|
+
.catch((err) => {
|
|
598
|
+
// Say so rather than swallowing: scratch rows accumulating forever is a
|
|
599
|
+
// slow leak nobody would otherwise notice.
|
|
600
|
+
// coercion-ok: failed GC degrades storage over time, never read correctness
|
|
601
|
+
console.warn("[resources] expired agent-scratch cleanup failed; will retry on a later read:", err?.message ?? err);
|
|
581
602
|
});
|
|
582
603
|
}
|
|
583
604
|
async function ensureTable() {
|
|
@@ -655,7 +676,7 @@ async function _doEnsureTable() {
|
|
|
655
676
|
"updated_at",
|
|
656
677
|
"expires_at",
|
|
657
678
|
]);
|
|
658
|
-
// `
|
|
679
|
+
// `scheduleExpiredAgentScratchCleanup` filters on exactly these two columns
|
|
659
680
|
// and, without this, full-scans `resources` — a table shared by every
|
|
660
681
|
// template and read from agent discovery, docs, chat scratch and remote-agent
|
|
661
682
|
// manifests. Its 60s throttle is a module-scope timestamp that starts at 0 in
|
|
@@ -669,7 +690,20 @@ async function _doEnsureTable() {
|
|
|
669
690
|
// coercion-ok: absence of an index degrades latency, never correctness
|
|
670
691
|
console.warn("[resources] could not ensure resources_visibility_expires_idx; scratch cleanup will full-scan:", err?.message ?? err);
|
|
671
692
|
});
|
|
672
|
-
// Seed default shared resources if they don't exist (INSERT OR IGNORE to avoid
|
|
693
|
+
// Seed default shared resources if they don't exist (INSERT OR IGNORE to avoid
|
|
694
|
+
// race conditions).
|
|
695
|
+
//
|
|
696
|
+
// Guarded by a durable marker: `_doEnsureTable` runs once per PROCESS, which on
|
|
697
|
+
// serverless is once per cold start, so this block was issuing ~10 writes and
|
|
698
|
+
// 2 migration scans per container to insert rows that had existed since day
|
|
699
|
+
// one (53,785 of them in one production sample). The marker makes it once per
|
|
700
|
+
// database, matching what the comments here already assumed.
|
|
701
|
+
//
|
|
702
|
+
// Consequence worth knowing: a default resource the user DELETES is no longer
|
|
703
|
+
// recreated on the next cold start. That silent resurrection was never
|
|
704
|
+
// intended — see `RESOURCE_SEED_VERSION` to force a re-seed.
|
|
705
|
+
if (await alreadySeeded(SHARED_SEED_KEY))
|
|
706
|
+
return;
|
|
673
707
|
const now = Date.now();
|
|
674
708
|
const seedSql = isPostgres()
|
|
675
709
|
? `INSERT INTO resources (id, path, owner, content, mime_type, size, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (path, owner) DO NOTHING`
|
|
@@ -797,8 +831,54 @@ async function _doEnsureTable() {
|
|
|
797
831
|
catch {
|
|
798
832
|
// Migration best-effort
|
|
799
833
|
}
|
|
834
|
+
await markSeeded(SHARED_SEED_KEY);
|
|
800
835
|
}
|
|
836
|
+
/**
|
|
837
|
+
* Bump when a default resource is ADDED, or when existing seed content must
|
|
838
|
+
* reach databases that already ran an earlier seed.
|
|
839
|
+
*
|
|
840
|
+
* The marker below records which version a database has been seeded at, so the
|
|
841
|
+
* seed runs once per database instead of once per process. Without a version, a
|
|
842
|
+
* newly added default would never reach an already-seeded deployment.
|
|
843
|
+
*/
|
|
844
|
+
const RESOURCE_SEED_VERSION = 1;
|
|
845
|
+
/**
|
|
846
|
+
* Per-process memo ON TOP of the durable marker, so a warm process doesn't even
|
|
847
|
+
* pay the marker read. The durable marker is what makes this correct across cold
|
|
848
|
+
* starts; this only avoids a repeat lookup within one process.
|
|
849
|
+
*/
|
|
801
850
|
const _personalSeeded = new Set();
|
|
851
|
+
function personalSeedKey(owner) {
|
|
852
|
+
return `resources-seeded:personal:v${RESOURCE_SEED_VERSION}:${owner.toLowerCase()}`;
|
|
853
|
+
}
|
|
854
|
+
const SHARED_SEED_KEY = `resources-seeded:shared:v${RESOURCE_SEED_VERSION}`;
|
|
855
|
+
/**
|
|
856
|
+
* Has this database already been seeded at the current version?
|
|
857
|
+
*
|
|
858
|
+
* A failed marker read returns `false` — "seed again" — because the seeds are
|
|
859
|
+
* `ON CONFLICT DO NOTHING` and therefore idempotent. Guessing "already seeded"
|
|
860
|
+
* on an unreadable marker would skip seeding a fresh database and leave it
|
|
861
|
+
* without its default AGENTS.md / LEARNINGS.md, which is not recoverable by
|
|
862
|
+
* retrying a read.
|
|
863
|
+
*/
|
|
864
|
+
async function alreadySeeded(key) {
|
|
865
|
+
try {
|
|
866
|
+
const row = await getSetting(key);
|
|
867
|
+
return row?.at !== undefined;
|
|
868
|
+
}
|
|
869
|
+
catch {
|
|
870
|
+
// coercion-ok: "not seeded" is the SAFE answer, and it is not indistinguishable from success — it re-runs an idempotent ON CONFLICT DO NOTHING seed, exactly the pre-marker behaviour. Guessing "already seeded" would leave a fresh database permanently without its default AGENTS.md / LEARNINGS.md, which no retry recovers.
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
async function markSeeded(key) {
|
|
875
|
+
try {
|
|
876
|
+
await putSetting(key, { at: Date.now() });
|
|
877
|
+
}
|
|
878
|
+
catch {
|
|
879
|
+
// coercion-ok: the marker is an optimization, not state anything reads for correctness. Failing to write it costs one repeat idempotent seed on the next cold start — the pre-marker behaviour — and the seed itself already succeeded, so there is no failure to report to the caller.
|
|
880
|
+
}
|
|
881
|
+
}
|
|
802
882
|
/**
|
|
803
883
|
* Seed personal AGENTS.md and LEARNINGS.md for a user if they don't exist.
|
|
804
884
|
* Called when listing resources or from the agent chat plugin.
|
|
@@ -810,6 +890,14 @@ export async function ensurePersonalDefaults(owner) {
|
|
|
810
890
|
return;
|
|
811
891
|
}
|
|
812
892
|
await ensureTable();
|
|
893
|
+
// The in-memory Set resets on every cold start, so on serverless this seed ran
|
|
894
|
+
// its 5 writes per container per owner, forever. The durable marker is what
|
|
895
|
+
// actually makes it once-per-owner.
|
|
896
|
+
const seedKey = personalSeedKey(owner);
|
|
897
|
+
if (await alreadySeeded(seedKey)) {
|
|
898
|
+
_personalSeeded.add(owner);
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
813
901
|
const client = getDbExec();
|
|
814
902
|
const now = Date.now();
|
|
815
903
|
const seedSql = isPostgres()
|
|
@@ -886,6 +974,7 @@ export async function ensurePersonalDefaults(owner) {
|
|
|
886
974
|
// retries instead of permanently skipping seeding. Seeds use INSERT OR IGNORE
|
|
887
975
|
// / ON CONFLICT DO NOTHING, so a concurrent re-run is harmless.
|
|
888
976
|
_personalSeeded.add(owner);
|
|
977
|
+
await markSeeded(seedKey);
|
|
889
978
|
}
|
|
890
979
|
function rowToResource(row) {
|
|
891
980
|
return {
|
|
@@ -932,7 +1021,7 @@ export async function resourceGet(id, options) {
|
|
|
932
1021
|
return localWorkspaceResourceById(id);
|
|
933
1022
|
}
|
|
934
1023
|
const client = getDbExec();
|
|
935
|
-
|
|
1024
|
+
scheduleExpiredAgentScratchCleanup(client);
|
|
936
1025
|
const { rows } = await client.execute({
|
|
937
1026
|
sql: `SELECT * FROM resources WHERE id = ?`,
|
|
938
1027
|
args: [id],
|
|
@@ -949,7 +1038,7 @@ export async function resourceGetByPath(owner, path, options) {
|
|
|
949
1038
|
return local;
|
|
950
1039
|
}
|
|
951
1040
|
const client = getDbExec();
|
|
952
|
-
|
|
1041
|
+
scheduleExpiredAgentScratchCleanup(client);
|
|
953
1042
|
const { rows } = await client.execute({
|
|
954
1043
|
sql: `SELECT * FROM resources WHERE owner = ? AND path = ?`,
|
|
955
1044
|
args: [owner, path],
|
|
@@ -1165,7 +1254,7 @@ export async function resourceDeleteByPath(owner, path) {
|
|
|
1165
1254
|
export async function resourceList(owner, pathPrefix, options) {
|
|
1166
1255
|
await ensureTable();
|
|
1167
1256
|
const client = getDbExec();
|
|
1168
|
-
|
|
1257
|
+
scheduleExpiredAgentScratchCleanup(client);
|
|
1169
1258
|
const visibilitySql = scratchFilterSql(options);
|
|
1170
1259
|
if (pathPrefix) {
|
|
1171
1260
|
const { rows } = await client.execute({
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
status?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
38
|
+
status?: undefined;
|
|
39
39
|
} | {
|
|
40
|
+
error?: undefined;
|
|
40
41
|
ok: boolean;
|
|
41
42
|
status: string;
|
|
42
|
-
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
error: string;
|
|
45
46
|
removed?: undefined;
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
error?: undefined;
|
|
48
49
|
ok: boolean;
|
|
49
50
|
removed: boolean;
|
|
50
|
-
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
+
ok?: undefined;
|
|
57
58
|
error: string;
|
|
58
59
|
note?: undefined;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
+
error?: undefined;
|
|
61
62
|
ok: boolean;
|
|
62
63
|
note?: undefined;
|
|
63
|
-
error?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
67
|
note: string;
|
|
67
|
-
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
+
error?: undefined;
|
|
98
99
|
ok: boolean;
|
|
99
100
|
key: string;
|
|
100
|
-
error?: undefined;
|
|
101
101
|
} | {
|
|
102
|
+
error?: undefined;
|
|
102
103
|
ok: boolean;
|
|
103
104
|
removed: boolean;
|
|
104
|
-
error?: undefined;
|
|
105
105
|
}>>;
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
import type { ActionEntry } from "../agent/production-agent.js";
|
|
29
|
+
import type { FrameworkToolGroup } from "../framework-tools.js";
|
|
29
30
|
/**
|
|
30
31
|
* Register a map of actions contributed by a published package.
|
|
31
32
|
*
|
|
@@ -80,6 +81,32 @@ export declare function loadActionsFromStaticRegistry(modules: Record<string, un
|
|
|
80
81
|
* passing to `createAgentChatPlugin({ actions })`.
|
|
81
82
|
*/
|
|
82
83
|
export declare function autoDiscoverActions(from: string): Promise<Record<string, ActionEntry>>;
|
|
84
|
+
/**
|
|
85
|
+
* Which `frameworkTools` switch owns each framework action kit.
|
|
86
|
+
*
|
|
87
|
+
* The group is stamped onto the entry as `frameworkGroup`, which is what lets
|
|
88
|
+
* one filter subtract a whole kit from every agent tool surface at once — the
|
|
89
|
+
* plugin spreads these registries at thirteen composition sites, and a
|
|
90
|
+
* per-site condition would be the same omission waiting to happen thirteen
|
|
91
|
+
* times. The tag also keeps these ~45 schemas out of the DEFAULT first-request
|
|
92
|
+
* tool list; they stay reachable through `tool-search`.
|
|
93
|
+
*
|
|
94
|
+
* Anything absent from this map is always-on and must be listed in
|
|
95
|
+
* `ALWAYS_ON_CORE_ACTIONS` instead. `action-discovery.spec.ts` fails when a new
|
|
96
|
+
* core action appears in neither, so "always-on" stays a decision someone made
|
|
97
|
+
* rather than the default that happens when a map goes un-updated.
|
|
98
|
+
*/
|
|
99
|
+
export declare const CORE_ACTION_GROUPS: Record<string, FrameworkToolGroup>;
|
|
100
|
+
/**
|
|
101
|
+
* Core actions with no `frameworkTools` switch, and why:
|
|
102
|
+
*
|
|
103
|
+
* - `upload-image` is load-bearing for ordinary work.
|
|
104
|
+
* - The email catalog is mounted everywhere on purpose so Dispatch can ask any
|
|
105
|
+
* app what it sends without that app opting in (see its comment below). It is
|
|
106
|
+
* a read surface, not the `email` group's send capability.
|
|
107
|
+
* - MCP tools and org service tokens are already governed by `disableMcp`.
|
|
108
|
+
*/
|
|
109
|
+
export declare const ALWAYS_ON_CORE_ACTIONS: ReadonlySet<string>;
|
|
83
110
|
export declare function mergeCoreSharingActions(registry: Record<string, ActionEntry>): Promise<void>;
|
|
84
111
|
/** @deprecated Use `autoDiscoverActions` instead */
|
|
85
112
|
export declare const autoDiscoverScripts: typeof autoDiscoverActions;
|
|
@@ -497,6 +497,92 @@ export async function autoDiscoverActions(from) {
|
|
|
497
497
|
}
|
|
498
498
|
return registry;
|
|
499
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* Which `frameworkTools` switch owns each framework action kit.
|
|
502
|
+
*
|
|
503
|
+
* The group is stamped onto the entry as `frameworkGroup`, which is what lets
|
|
504
|
+
* one filter subtract a whole kit from every agent tool surface at once — the
|
|
505
|
+
* plugin spreads these registries at thirteen composition sites, and a
|
|
506
|
+
* per-site condition would be the same omission waiting to happen thirteen
|
|
507
|
+
* times. The tag also keeps these ~45 schemas out of the DEFAULT first-request
|
|
508
|
+
* tool list; they stay reachable through `tool-search`.
|
|
509
|
+
*
|
|
510
|
+
* Anything absent from this map is always-on and must be listed in
|
|
511
|
+
* `ALWAYS_ON_CORE_ACTIONS` instead. `action-discovery.spec.ts` fails when a new
|
|
512
|
+
* core action appears in neither, so "always-on" stays a decision someone made
|
|
513
|
+
* rather than the default that happens when a map goes un-updated.
|
|
514
|
+
*/
|
|
515
|
+
export const CORE_ACTION_GROUPS = {
|
|
516
|
+
"share-resource": "sharing",
|
|
517
|
+
"unshare-resource": "sharing",
|
|
518
|
+
"list-resource-shares": "sharing",
|
|
519
|
+
"set-resource-visibility": "sharing",
|
|
520
|
+
"create-agent-resource-link": "sharing",
|
|
521
|
+
"get-feature-flags": "featureFlags",
|
|
522
|
+
"list-feature-flags": "featureFlags",
|
|
523
|
+
"set-feature-flag": "featureFlags",
|
|
524
|
+
"list-recurring-jobs": "automation",
|
|
525
|
+
"manage-recurring-job": "automation",
|
|
526
|
+
"run-automation-now": "automation",
|
|
527
|
+
"list-automation-runs": "automation",
|
|
528
|
+
"list-automations": "automation",
|
|
529
|
+
"manage-automation": "automation",
|
|
530
|
+
"context-manifest-get": "contextXray",
|
|
531
|
+
"context-preview-get": "contextXray",
|
|
532
|
+
"context-pin": "contextXray",
|
|
533
|
+
"context-evict": "contextXray",
|
|
534
|
+
"context-restore": "contextXray",
|
|
535
|
+
"context-report": "contextXray",
|
|
536
|
+
"get-localization-preference": "localization",
|
|
537
|
+
"set-localization-preference": "localization",
|
|
538
|
+
// Profile, credentials, and appearance share one switch: an app that hides
|
|
539
|
+
// its profile surface from the agent hides password management with it.
|
|
540
|
+
"get-user-profile": "userProfile",
|
|
541
|
+
"update-user-profile": "userProfile",
|
|
542
|
+
"get-auth-methods": "userProfile",
|
|
543
|
+
"set-password": "userProfile",
|
|
544
|
+
"change-password": "userProfile",
|
|
545
|
+
"change-appearance": "userProfile",
|
|
546
|
+
"list-audit-events": "audit",
|
|
547
|
+
"get-audit-event": "audit",
|
|
548
|
+
"export-audit-events": "audit",
|
|
549
|
+
"create-resource-version": "history",
|
|
550
|
+
"list-resource-versions": "history",
|
|
551
|
+
"get-resource-version": "history",
|
|
552
|
+
"restore-resource-version": "history",
|
|
553
|
+
"list-resource-history": "history",
|
|
554
|
+
"list-review-comments": "review",
|
|
555
|
+
"create-review-comment": "review",
|
|
556
|
+
"reply-review-comment": "review",
|
|
557
|
+
"resolve-review-thread": "review",
|
|
558
|
+
"delete-review-comment": "review",
|
|
559
|
+
"consume-review-feedback": "review",
|
|
560
|
+
"get-review-feedback": "review",
|
|
561
|
+
"set-review-status": "review",
|
|
562
|
+
"send-review-thread-to-agent": "review",
|
|
563
|
+
};
|
|
564
|
+
/**
|
|
565
|
+
* Core actions with no `frameworkTools` switch, and why:
|
|
566
|
+
*
|
|
567
|
+
* - `upload-image` is load-bearing for ordinary work.
|
|
568
|
+
* - The email catalog is mounted everywhere on purpose so Dispatch can ask any
|
|
569
|
+
* app what it sends without that app opting in (see its comment below). It is
|
|
570
|
+
* a read surface, not the `email` group's send capability.
|
|
571
|
+
* - MCP tools and org service tokens are already governed by `disableMcp`.
|
|
572
|
+
*/
|
|
573
|
+
export const ALWAYS_ON_CORE_ACTIONS = new Set([
|
|
574
|
+
"upload-image",
|
|
575
|
+
"list-transactional-emails",
|
|
576
|
+
"render-transactional-email-preview",
|
|
577
|
+
"list-email-log",
|
|
578
|
+
"list-email-activity",
|
|
579
|
+
"list-email-engagement",
|
|
580
|
+
"create-org-service-token",
|
|
581
|
+
"list-org-service-tokens",
|
|
582
|
+
"revoke-org-service-token",
|
|
583
|
+
"list-mcp-tools",
|
|
584
|
+
"call-mcp-tool",
|
|
585
|
+
]);
|
|
500
586
|
export async function mergeCoreSharingActions(registry) {
|
|
501
587
|
const entries = [
|
|
502
588
|
["share-resource", () => import("../sharing/actions/share-resource.js")],
|
|
@@ -732,6 +818,9 @@ export async function mergeCoreSharingActions(registry) {
|
|
|
732
818
|
// actions' `toolCallable: false` (audit-H5) is dropped and the
|
|
733
819
|
// tools-iframe bridge 403 in action-routes.ts never fires.
|
|
734
820
|
...preserveActionFlags(def),
|
|
821
|
+
...(CORE_ACTION_GROUPS[name]
|
|
822
|
+
? { frameworkGroup: CORE_ACTION_GROUPS[name] }
|
|
823
|
+
: {}),
|
|
735
824
|
};
|
|
736
825
|
}
|
|
737
826
|
}
|
|
@@ -117,5 +117,16 @@ export declare function createA2AEngineToolSurface(availableTools: EngineTool[],
|
|
|
117
117
|
tools: EngineTool[];
|
|
118
118
|
availableTools: EngineTool[];
|
|
119
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* The first-request tool catalog: an explicit `initialToolNames` verbatim, or
|
|
122
|
+
* the app's OWN actions by default.
|
|
123
|
+
*
|
|
124
|
+
* "Its own actions" excludes the framework kits. They arrive in this same
|
|
125
|
+
* registry through `autoDiscoverActions` -> `mergeCoreSharingActions`, so the
|
|
126
|
+
* plain `Object.keys` default promoted ~45 sharing/review/history/flag schemas
|
|
127
|
+
* into every app's first request whether or not the app had those surfaces. They
|
|
128
|
+
* remain in `availableTools` and are still found by `tool-search`; an app that
|
|
129
|
+
* wants one on turn one names it in `initialToolNames`.
|
|
130
|
+
*/
|
|
120
131
|
export declare function resolveInitialToolNames(templateActions: Record<string, ActionEntry>, configured?: string[]): string[];
|
|
121
132
|
export {};
|
|
@@ -5,6 +5,7 @@ import { resolveMainChatMaxOutputTokens } from "../../agent/engine/output-tokens
|
|
|
5
5
|
import { filterInitialEngineTools, resolveAgentRequestReasoningEffort, } from "../../agent/production-agent.js";
|
|
6
6
|
import { runAgentLoopDirectWithSoftTimeout } from "../../agent/run-loop-with-resume.js";
|
|
7
7
|
import { resolveRunSoftTimeoutMs } from "../../agent/run-manager.js";
|
|
8
|
+
import { isFrameworkGroupedAction } from "../../framework-tools.js";
|
|
8
9
|
import { isAuthenticatedReadAction, isAutoReadExcludedActionName, } from "../../mcp/build-server.js";
|
|
9
10
|
import { withConfiguredAppBasePath } from "../app-base-path.js";
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -389,6 +390,21 @@ export function createA2AEngineToolSurface(availableTools, initialToolNames) {
|
|
|
389
390
|
availableTools,
|
|
390
391
|
};
|
|
391
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* The first-request tool catalog: an explicit `initialToolNames` verbatim, or
|
|
395
|
+
* the app's OWN actions by default.
|
|
396
|
+
*
|
|
397
|
+
* "Its own actions" excludes the framework kits. They arrive in this same
|
|
398
|
+
* registry through `autoDiscoverActions` -> `mergeCoreSharingActions`, so the
|
|
399
|
+
* plain `Object.keys` default promoted ~45 sharing/review/history/flag schemas
|
|
400
|
+
* into every app's first request whether or not the app had those surfaces. They
|
|
401
|
+
* remain in `availableTools` and are still found by `tool-search`; an app that
|
|
402
|
+
* wants one on turn one names it in `initialToolNames`.
|
|
403
|
+
*/
|
|
392
404
|
export function resolveInitialToolNames(templateActions, configured) {
|
|
393
|
-
|
|
405
|
+
if (configured)
|
|
406
|
+
return configured;
|
|
407
|
+
return Object.entries(templateActions)
|
|
408
|
+
.filter(([, entry]) => !isFrameworkGroupedAction(entry))
|
|
409
|
+
.map(([name]) => name);
|
|
394
410
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ActionEntry } from "../../agent/production-agent.js";
|
|
2
|
+
import type { FrameworkToolGroup } from "../../framework-tools.js";
|
|
2
3
|
import type { DatabaseToolsOption } from "../../scripts/db/tool-mode.js";
|
|
3
4
|
import { type PromptExamples } from "../prompts/index.js";
|
|
4
5
|
import { resolveInitialToolNames } from "./action-filters-a2a.js";
|
|
@@ -15,6 +16,7 @@ import { createDataWidgetActionEntries } from "./context-tools.js";
|
|
|
15
16
|
export declare function buildFrameworkPrompts(examples?: PromptExamples, options?: {
|
|
16
17
|
databaseTools?: DatabaseToolsOption;
|
|
17
18
|
extensionTools?: boolean;
|
|
19
|
+
disabledFrameworkGroups?: ReadonlySet<FrameworkToolGroup>;
|
|
18
20
|
}): {
|
|
19
21
|
FRAMEWORK_CORE: string;
|
|
20
22
|
FRAMEWORK_CORE_COMPACT: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ActionEntry } from "../../agent/production-agent.js";
|
|
2
2
|
import type { AgentLoopFinalResponseGuard } from "../../agent/production-agent.js";
|
|
3
3
|
import type { AgentChatAttachment, AgentChatReference, MentionProvider } from "../../agent/types.js";
|
|
4
|
+
import type { FrameworkToolsConfig } from "../../framework-tools.js";
|
|
4
5
|
import type { ExternalAgentPolicy } from "../../mcp/external-agent-policy.js";
|
|
5
6
|
import type { DatabaseToolsOption } from "../../scripts/db/tool-mode.js";
|
|
6
7
|
import type { PromptExamples } from "../prompts/index.js";
|
|
@@ -236,6 +237,29 @@ export interface AgentChatPluginOptions {
|
|
|
236
237
|
* Defaults to `false`.
|
|
237
238
|
*/
|
|
238
239
|
nativeActionsInDev?: boolean;
|
|
240
|
+
/**
|
|
241
|
+
* Which of the framework's OWN agent tools this app exposes — raw SQL,
|
|
242
|
+
* extensions, sharing, review comments, version history, feature flags,
|
|
243
|
+
* localization, audit, context X-Ray, profile, automations, docs, resources,
|
|
244
|
+
* web, cross-app delegation, chat, email.
|
|
245
|
+
*
|
|
246
|
+
* Every group defaults to today's behavior, so omitting this leaves the tool
|
|
247
|
+
* surface unchanged. `"minimal"` (or `{ preset: "minimal" }`) turns them all
|
|
248
|
+
* off for voice-first and single-purpose apps; an explicit group key wins over
|
|
249
|
+
* the preset.
|
|
250
|
+
*
|
|
251
|
+
* Disabling a group removes it from the AGENT surfaces only — chat, MCP, A2A,
|
|
252
|
+
* background runs. The matching HTTP action routes stay mounted because the UI
|
|
253
|
+
* reaches them through client hooks. Weigh the parity cost first: the
|
|
254
|
+
* framework's contract is that anything the UI can do, the agent can do, so
|
|
255
|
+
* `sharing: false` alongside a visible `ShareButton` is a deliberate break and
|
|
256
|
+
* only makes sense when the app has no such surface.
|
|
257
|
+
*
|
|
258
|
+
* Independent of this option, framework tools are no longer promoted into the
|
|
259
|
+
* first model request by default — they are reachable through `tool-search`,
|
|
260
|
+
* or by naming them in `initialToolNames`.
|
|
261
|
+
*/
|
|
262
|
+
frameworkTools?: FrameworkToolsConfig;
|
|
239
263
|
/**
|
|
240
264
|
* Expose raw SQL/native database tools to the app agent.
|
|
241
265
|
*
|
|
@@ -244,6 +268,9 @@ export interface AgentChatPluginOptions {
|
|
|
244
268
|
* `true`) to expose `db-exec`/`db-patch` for scoped raw SQL maintenance.
|
|
245
269
|
* Set to `"off"` (also `false`) for chat-first apps that want agents to use
|
|
246
270
|
* typed actions only.
|
|
271
|
+
*
|
|
272
|
+
* @deprecated Use `frameworkTools: { database: … }`. Still honored for one
|
|
273
|
+
* minor; setting both to conflicting values throws at plugin init.
|
|
247
274
|
*/
|
|
248
275
|
databaseTools?: DatabaseToolsOption;
|
|
249
276
|
/**
|
|
@@ -252,6 +279,9 @@ export interface AgentChatPluginOptions {
|
|
|
252
279
|
* false. Set to true for apps that intentionally let the LLM create or
|
|
253
280
|
* manage sandboxed extension mini-apps. Core extension routes may still be
|
|
254
281
|
* mounted for compatibility and app-owned surfaces.
|
|
282
|
+
*
|
|
283
|
+
* @deprecated Use `frameworkTools: { extensions: … }`. Still honored for one
|
|
284
|
+
* minor; setting both to conflicting values throws at plugin init.
|
|
255
285
|
*/
|
|
256
286
|
extensionTools?: boolean;
|
|
257
287
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FrameworkToolGroup } from "../../framework-tools.js";
|
|
1
2
|
import type { ContextGovernanceTier, ContextManifestSourceRef, ContextSystemProvenance } from "../../shared/context-xray.js";
|
|
2
3
|
export declare const COMPACT_PROMPT_RESOURCE_MAX_CHARS = 6000;
|
|
3
4
|
export interface PromptContextProviderContext {
|
|
@@ -89,4 +90,6 @@ export declare function resourceScopeForOwner(owner: string, currentOwner?: stri
|
|
|
89
90
|
* AGENTS.md and restarting the server is all it takes; Vite HMR invalidates
|
|
90
91
|
* the bundle in dev so changes land instantly.
|
|
91
92
|
*/
|
|
92
|
-
export declare function loadResourcesForPrompt(owner: string, compact?: boolean, selfAppId?: string, orgId?: string | null
|
|
93
|
+
export declare function loadResourcesForPrompt(owner: string, compact?: boolean, selfAppId?: string, orgId?: string | null, opts?: {
|
|
94
|
+
disabledFrameworkGroups?: ReadonlySet<FrameworkToolGroup>;
|
|
95
|
+
}): Promise<string>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { frameworkGroupEnabled, } from "../../framework-tools.js";
|
|
1
2
|
import { getFrontmatterValue, getSkillNameFromPath, parseFrontmatter, } from "../../resources/metadata.js";
|
|
2
3
|
import { ensurePersonalDefaults, organizationIdFromResourceOwner, resourceGet, resourceGetByPath, resourceList, resourceListAccessible, SHARED_OWNER, sharedResourceOwner, WORKSPACE_OWNER, } from "../../resources/store.js";
|
|
3
4
|
import { discoverAgents } from "../agent-discovery.js";
|
|
@@ -600,7 +601,7 @@ async function loadResourceIndexForPrompt(owner, scope) {
|
|
|
600
601
|
* AGENTS.md and restarting the server is all it takes; Vite HMR invalidates
|
|
601
602
|
* the bundle in dev so changes land instantly.
|
|
602
603
|
*/
|
|
603
|
-
export async function loadResourcesForPrompt(owner, compact = false, selfAppId, orgId = getRequestOrgId() ?? null) {
|
|
604
|
+
export async function loadResourcesForPrompt(owner, compact = false, selfAppId, orgId = getRequestOrgId() ?? null, opts) {
|
|
604
605
|
await ensurePersonalDefaults(owner);
|
|
605
606
|
const sections = [];
|
|
606
607
|
const addSection = (content, governance = "inherited") => {
|
|
@@ -774,7 +775,12 @@ export async function loadResourcesForPrompt(owner, compact = false, selfAppId,
|
|
|
774
775
|
orgId,
|
|
775
776
|
}));
|
|
776
777
|
try {
|
|
777
|
-
|
|
778
|
+
// Both tools this block names by name come from the `workspaceApps` group.
|
|
779
|
+
// With that group off there is no `call-agent` to delegate through, so the
|
|
780
|
+
// block would only teach a capability the request cannot carry.
|
|
781
|
+
const agents = frameworkGroupEnabled(opts?.disabledFrameworkGroups, "workspaceApps")
|
|
782
|
+
? (await discoverAgents(selfAppId)).slice(0, 30)
|
|
783
|
+
: [];
|
|
778
784
|
if (agents.length > 0) {
|
|
779
785
|
const lines = agents.map((agent) => `- ${agent.name} (${agent.id}) — ${agent.description || "Connected A2A app"}`);
|
|
780
786
|
// Nothing else in the prompt or the initial tool surface tells the agent
|