@agent-native/core 0.59.1 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +63 -0
- package/dist/a2a/invoke.d.ts.map +1 -0
- package/dist/a2a/invoke.js +157 -0
- package/dist/a2a/invoke.js.map +1 -0
- package/dist/agent/run-store.d.ts +15 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +28 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +21 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +128 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/agent.d.ts +23 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +300 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/agents.d.ts +14 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +95 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +264 -2
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/create.d.ts +3 -2
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +154 -83
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +50 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/invoke.d.ts +26 -0
- package/dist/cli/invoke.d.ts.map +1 -0
- package/dist/cli/invoke.js +227 -0
- package/dist/cli/invoke.js.map +1 -0
- package/dist/cli/templates-meta.d.ts +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +9 -8
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/workspacify.d.ts +1 -1
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +6 -6
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +5 -4
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/blocks/library/diagram.d.ts.map +1 -1
- package/dist/client/blocks/library/diagram.js +23 -17
- package/dist/client/blocks/library/diagram.js.map +1 -1
- package/dist/client/blocks/types.d.ts +2 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts +13 -0
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +41 -0
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +2 -2
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +102 -0
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +84 -0
- package/dist/provider-api/actions/github-repo-files.d.ts.map +1 -0
- package/dist/provider-api/actions/github-repo-files.js +213 -0
- package/dist/provider-api/actions/github-repo-files.js.map +1 -0
- package/dist/provider-api/github-repo.d.ts +11 -0
- package/dist/provider-api/github-repo.d.ts.map +1 -0
- package/dist/provider-api/github-repo.js +553 -0
- package/dist/provider-api/github-repo.js.map +1 -0
- package/dist/provider-api/index.d.ts +184 -11
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +519 -0
- package/dist/provider-api/index.js.map +1 -1
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +38 -13
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +11 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +32 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +297 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +17 -7
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +18 -98
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/styles/blocks.css +30 -8
- package/dist/styles/rich-markdown-editor.css +10 -4
- package/dist/templates/{starter-shell-sync.spec.ts → chat-shell-sync.spec.ts} +21 -21
- package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -5
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/default/AGENTS.md +22 -1
- package/dist/templates/default/actions/hello.ts +1 -1
- package/dist/templates/default/actions/navigate.ts +1 -1
- package/dist/templates/default/actions/view-screen.ts +1 -1
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/headless/.env.example +4 -0
- package/dist/templates/headless/.prettierrc +5 -0
- package/dist/templates/headless/AGENTS.md +58 -0
- package/dist/templates/headless/DEVELOPING.md +22 -0
- package/dist/templates/headless/_gitignore +36 -0
- package/dist/templates/headless/actions/hello.ts +14 -0
- package/dist/templates/headless/actions/run.ts +3 -0
- package/dist/templates/headless/package.json +22 -0
- package/dist/templates/headless/tsconfig.json +7 -0
- package/dist/templates/ui-primitives-sync.spec.ts +2 -2
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -5
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +93 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +1 -1
- package/dist/templates/workspace-core/AGENTS.md +20 -3
- package/dist/templates/workspace-core/src/server/index.ts +1 -1
- package/dist/templates/workspace-root/AGENTS.md +25 -5
- package/dist/templates/workspace-root/README.md +7 -7
- package/dist/triggers/dispatcher.d.ts +2 -3
- package/dist/triggers/dispatcher.d.ts.map +1 -1
- package/dist/triggers/dispatcher.js +2 -3
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/triggers/routes.d.ts +38 -0
- package/dist/triggers/routes.d.ts.map +1 -0
- package/dist/triggers/routes.js +202 -0
- package/dist/triggers/routes.js.map +1 -0
- package/docs/AGENTS.md +57 -0
- package/docs/SKILL.md +40 -0
- package/docs/content/a2a-protocol.md +1 -1
- package/docs/content/actions.md +48 -8
- package/docs/content/agent-surfaces.md +76 -14
- package/docs/content/cli-adapters.md +1 -1
- package/docs/content/cloneable-saas.md +5 -4
- package/docs/content/code-agents-ui.md +1 -1
- package/docs/content/components.md +1 -1
- package/docs/content/context-awareness.md +1 -1
- package/docs/content/creating-templates.md +9 -7
- package/docs/content/drop-in-agent.md +1 -1
- package/docs/content/faq.md +6 -4
- package/docs/content/getting-started.md +63 -73
- package/docs/content/key-concepts.md +24 -24
- package/docs/content/native-chat-ui.md +4 -4
- package/docs/content/pure-agent-apps.md +34 -10
- package/docs/content/security.md +1 -1
- package/docs/content/server.md +1 -1
- package/docs/content/template-chat.md +85 -0
- package/docs/content/template-dispatch.md +1 -1
- package/docs/content/tracking.md +1 -1
- package/docs/content/what-is-agent-native.md +7 -6
- package/package.json +10 -1
- package/src/templates/{starter-shell-sync.spec.ts → chat-shell-sync.spec.ts} +21 -21
- package/src/templates/default/.agents/skills/actions/SKILL.md +5 -5
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/default/AGENTS.md +22 -1
- package/src/templates/default/actions/hello.ts +1 -1
- package/src/templates/default/actions/navigate.ts +1 -1
- package/src/templates/default/actions/view-screen.ts +1 -1
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/headless/.env.example +4 -0
- package/src/templates/headless/.prettierrc +5 -0
- package/src/templates/headless/AGENTS.md +58 -0
- package/src/templates/headless/DEVELOPING.md +22 -0
- package/src/templates/headless/_gitignore +36 -0
- package/src/templates/headless/actions/hello.ts +14 -0
- package/src/templates/headless/actions/run.ts +3 -0
- package/src/templates/headless/package.json +22 -0
- package/src/templates/headless/tsconfig.json +7 -0
- package/src/templates/ui-primitives-sync.spec.ts +2 -2
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -5
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +63 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +93 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +1 -1
- package/src/templates/workspace-core/AGENTS.md +20 -3
- package/src/templates/workspace-core/src/server/index.ts +1 -1
- package/src/templates/workspace-root/AGENTS.md +25 -5
- package/src/templates/workspace-root/README.md +7 -7
- package/docs/content/template-starter.md +0 -78
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/triggers/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAkBZ,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,yBAAyB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AA2HD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAahC;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAkD9B;AAWD,wBAAgB,wBAAwB;;;;IA8DvC"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { defineEventHandler, getMethod, setResponseStatus, } from "h3";
|
|
2
|
+
import { readBody } from "../server/h3-helpers.js";
|
|
3
|
+
import { getSession } from "../server/auth.js";
|
|
4
|
+
import { getDbExec } from "../db/client.js";
|
|
5
|
+
import { nextOccurrence, describeCron, isValidCron } from "../jobs/cron.js";
|
|
6
|
+
import { getOrgContext } from "../org/context.js";
|
|
7
|
+
import { resourceGetByPath, resourceListAllOwners, resourcePut, SHARED_OWNER, } from "../resources/store.js";
|
|
8
|
+
import { buildTriggerContent, parseTriggerFrontmatter, refreshEventSubscriptions, } from "./dispatcher.js";
|
|
9
|
+
function automationName(path) {
|
|
10
|
+
return path.replace(/^jobs\//, "").replace(/\.md$/, "");
|
|
11
|
+
}
|
|
12
|
+
function normalizeAutomationPath(input) {
|
|
13
|
+
const rawPath = input.path ?? (input.name ? `jobs/${input.name}.md` : "");
|
|
14
|
+
const path = rawPath.replace(/^\/+/, "");
|
|
15
|
+
if (!path.startsWith("jobs/") ||
|
|
16
|
+
!path.endsWith(".md") ||
|
|
17
|
+
path.endsWith(".keep") ||
|
|
18
|
+
path.includes("..")) {
|
|
19
|
+
throw Object.assign(new Error("A valid jobs/*.md automation path is required"), {
|
|
20
|
+
statusCode: 400,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return path;
|
|
24
|
+
}
|
|
25
|
+
function scheduleDescription(schedule) {
|
|
26
|
+
if (!schedule)
|
|
27
|
+
return undefined;
|
|
28
|
+
try {
|
|
29
|
+
return describeCron(schedule);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return schedule;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function nextRunForMeta(meta) {
|
|
36
|
+
if (meta.nextRun)
|
|
37
|
+
return meta.nextRun;
|
|
38
|
+
if (meta.enabled &&
|
|
39
|
+
meta.triggerType !== "event" &&
|
|
40
|
+
meta.schedule &&
|
|
41
|
+
isValidCron(meta.schedule)) {
|
|
42
|
+
try {
|
|
43
|
+
return nextOccurrence(meta.schedule).toISOString();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
async function currentUserCanUpdateAutomation(event, userEmail, resourceOwner, meta) {
|
|
52
|
+
if (resourceOwner === userEmail)
|
|
53
|
+
return true;
|
|
54
|
+
if (resourceOwner !== SHARED_OWNER)
|
|
55
|
+
return false;
|
|
56
|
+
if (meta.createdBy &&
|
|
57
|
+
meta.createdBy.toLowerCase() === userEmail.toLowerCase()) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
let orgId = meta.orgId;
|
|
61
|
+
if (!orgId) {
|
|
62
|
+
try {
|
|
63
|
+
orgId = (await getOrgContext(event)).orgId ?? undefined;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
orgId = undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!orgId)
|
|
70
|
+
return false;
|
|
71
|
+
try {
|
|
72
|
+
const { rows } = await getDbExec().execute({
|
|
73
|
+
sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
|
|
74
|
+
args: [orgId, userEmail.toLowerCase()],
|
|
75
|
+
});
|
|
76
|
+
const role = String(rows[0]?.role ?? "").toLowerCase();
|
|
77
|
+
return role === "owner" || role === "admin";
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function resourceToAutomationItem(event, userEmail, resource) {
|
|
84
|
+
const { meta, body } = parseTriggerFrontmatter(resource.content);
|
|
85
|
+
return {
|
|
86
|
+
id: resource.id,
|
|
87
|
+
name: automationName(resource.path),
|
|
88
|
+
path: resource.path,
|
|
89
|
+
owner: resource.owner,
|
|
90
|
+
canUpdate: await currentUserCanUpdateAutomation(event, userEmail, resource.owner, meta),
|
|
91
|
+
triggerType: meta.triggerType,
|
|
92
|
+
event: meta.event,
|
|
93
|
+
schedule: meta.schedule || undefined,
|
|
94
|
+
scheduleDescription: scheduleDescription(meta.schedule),
|
|
95
|
+
condition: meta.condition,
|
|
96
|
+
mode: meta.mode,
|
|
97
|
+
domain: meta.domain,
|
|
98
|
+
enabled: meta.enabled,
|
|
99
|
+
lastStatus: meta.lastStatus,
|
|
100
|
+
lastRun: meta.lastRun,
|
|
101
|
+
lastError: meta.lastError,
|
|
102
|
+
nextRun: nextRunForMeta(meta),
|
|
103
|
+
createdBy: meta.createdBy,
|
|
104
|
+
body,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export async function listAutomationsForOwner(event, userEmail) {
|
|
108
|
+
const allResources = await resourceListAllOwners("jobs/");
|
|
109
|
+
const resources = allResources.filter((resource) => (resource.owner === userEmail || resource.owner === SHARED_OWNER) &&
|
|
110
|
+
resource.path.endsWith(".md") &&
|
|
111
|
+
!resource.path.endsWith(".keep"));
|
|
112
|
+
return Promise.all(resources.map((resource) => resourceToAutomationItem(event, userEmail, resource)));
|
|
113
|
+
}
|
|
114
|
+
export async function setAutomationEnabledForOwner(event, userEmail, input) {
|
|
115
|
+
if (typeof input.enabled !== "boolean") {
|
|
116
|
+
throw Object.assign(new Error("enabled must be a boolean"), {
|
|
117
|
+
statusCode: 400,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const path = normalizeAutomationPath(input);
|
|
121
|
+
const requestedOwner = input.owner === SHARED_OWNER ? SHARED_OWNER : userEmail;
|
|
122
|
+
const resource = await resourceGetByPath(requestedOwner, path);
|
|
123
|
+
if (!resource) {
|
|
124
|
+
throw Object.assign(new Error("Automation not found"), { statusCode: 404 });
|
|
125
|
+
}
|
|
126
|
+
const { meta, body } = parseTriggerFrontmatter(resource.content);
|
|
127
|
+
const allowed = await currentUserCanUpdateAutomation(event, userEmail, resource.owner, meta);
|
|
128
|
+
if (!allowed) {
|
|
129
|
+
throw Object.assign(new Error("Only the automation creator or an org admin can update it."), { statusCode: 403 });
|
|
130
|
+
}
|
|
131
|
+
meta.enabled = input.enabled;
|
|
132
|
+
if (meta.enabled &&
|
|
133
|
+
meta.triggerType !== "event" &&
|
|
134
|
+
meta.schedule &&
|
|
135
|
+
isValidCron(meta.schedule)) {
|
|
136
|
+
meta.nextRun = nextOccurrence(meta.schedule).toISOString();
|
|
137
|
+
}
|
|
138
|
+
await resourcePut(resource.owner, resource.path, buildTriggerContent(meta, body));
|
|
139
|
+
await refreshEventSubscriptions();
|
|
140
|
+
return resourceToAutomationItem(event, userEmail, {
|
|
141
|
+
...resource,
|
|
142
|
+
content: buildTriggerContent(meta, body),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function routeError(event, err, fallback) {
|
|
146
|
+
const statusCode = typeof err?.statusCode === "number"
|
|
147
|
+
? err.statusCode
|
|
148
|
+
: 500;
|
|
149
|
+
setResponseStatus(event, statusCode);
|
|
150
|
+
return { error: err?.message ?? fallback };
|
|
151
|
+
}
|
|
152
|
+
export function createAutomationsHandler() {
|
|
153
|
+
return defineEventHandler(async (event) => {
|
|
154
|
+
const method = getMethod(event);
|
|
155
|
+
const pathname = (event.path || event.url?.pathname || "")
|
|
156
|
+
.split("?")[0]
|
|
157
|
+
.replace(/^\/+/, "")
|
|
158
|
+
.replace(/\/+$/, "");
|
|
159
|
+
const session = await getSession(event).catch(() => null);
|
|
160
|
+
if (!session?.email) {
|
|
161
|
+
setResponseStatus(event, 401);
|
|
162
|
+
return { error: "Unauthenticated" };
|
|
163
|
+
}
|
|
164
|
+
if ((pathname === "fire-test" || pathname.endsWith("/fire-test")) &&
|
|
165
|
+
method === "POST") {
|
|
166
|
+
try {
|
|
167
|
+
const { emit } = await import("../event-bus/index.js");
|
|
168
|
+
const body = (await readBody(event).catch(() => ({})));
|
|
169
|
+
emit("test.event.fired", { data: body.data ?? {} }, { owner: session.email });
|
|
170
|
+
return { ok: true };
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
return routeError(event, err, "Failed to emit test event");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (method === "GET") {
|
|
177
|
+
try {
|
|
178
|
+
return await listAutomationsForOwner(event, session.email);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
return routeError(event, err, "Failed to list automations");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (method === "PATCH" || method === "PUT") {
|
|
185
|
+
try {
|
|
186
|
+
const body = (await readBody(event).catch(() => ({})));
|
|
187
|
+
return await setAutomationEnabledForOwner(event, session.email, {
|
|
188
|
+
owner: body?.owner,
|
|
189
|
+
path: body?.path,
|
|
190
|
+
name: body?.name,
|
|
191
|
+
enabled: body?.enabled,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
return routeError(event, err, "Failed to update automation");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
setResponseStatus(event, 405);
|
|
199
|
+
return { error: "Method not allowed" };
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/triggers/routes.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n getMethod,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { getSession } from \"../server/auth.js\";\nimport { getDbExec } from \"../db/client.js\";\nimport { nextOccurrence, describeCron, isValidCron } from \"../jobs/cron.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport {\n resourceGetByPath,\n resourceListAllOwners,\n resourcePut,\n SHARED_OWNER,\n type Resource,\n} from \"../resources/store.js\";\nimport {\n buildTriggerContent,\n parseTriggerFrontmatter,\n refreshEventSubscriptions,\n} from \"./dispatcher.js\";\nimport type { TriggerFrontmatter } from \"./types.js\";\n\nexport interface AutomationRouteItem {\n id: string;\n name: string;\n path: string;\n owner: string;\n canUpdate: boolean;\n triggerType: TriggerFrontmatter[\"triggerType\"];\n event?: string;\n schedule?: string;\n scheduleDescription?: string;\n condition?: string;\n mode: TriggerFrontmatter[\"mode\"];\n domain?: string;\n enabled: boolean;\n lastStatus?: TriggerFrontmatter[\"lastStatus\"];\n lastRun?: string;\n lastError?: string;\n nextRun?: string;\n createdBy?: string;\n body: string;\n}\n\ninterface SetAutomationEnabledInput {\n owner?: string;\n path?: string;\n name?: string;\n enabled: boolean;\n}\n\nfunction automationName(path: string): string {\n return path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n}\n\nfunction normalizeAutomationPath(input: SetAutomationEnabledInput): string {\n const rawPath = input.path ?? (input.name ? `jobs/${input.name}.md` : \"\");\n const path = rawPath.replace(/^\\/+/, \"\");\n if (\n !path.startsWith(\"jobs/\") ||\n !path.endsWith(\".md\") ||\n path.endsWith(\".keep\") ||\n path.includes(\"..\")\n ) {\n throw Object.assign(\n new Error(\"A valid jobs/*.md automation path is required\"),\n {\n statusCode: 400,\n },\n );\n }\n return path;\n}\n\nfunction scheduleDescription(schedule: string | undefined): string | undefined {\n if (!schedule) return undefined;\n try {\n return describeCron(schedule);\n } catch {\n return schedule;\n }\n}\n\nfunction nextRunForMeta(meta: TriggerFrontmatter): string | undefined {\n if (meta.nextRun) return meta.nextRun;\n if (\n meta.enabled &&\n meta.triggerType !== \"event\" &&\n meta.schedule &&\n isValidCron(meta.schedule)\n ) {\n try {\n return nextOccurrence(meta.schedule).toISOString();\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nasync function currentUserCanUpdateAutomation(\n event: H3Event,\n userEmail: string,\n resourceOwner: string,\n meta: TriggerFrontmatter,\n): Promise<boolean> {\n if (resourceOwner === userEmail) return true;\n if (resourceOwner !== SHARED_OWNER) return false;\n\n if (\n meta.createdBy &&\n meta.createdBy.toLowerCase() === userEmail.toLowerCase()\n ) {\n return true;\n }\n\n let orgId = meta.orgId;\n if (!orgId) {\n try {\n orgId = (await getOrgContext(event)).orgId ?? undefined;\n } catch {\n orgId = undefined;\n }\n }\n if (!orgId) return false;\n\n try {\n const { rows } = await getDbExec().execute({\n sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, userEmail.toLowerCase()],\n });\n const role = String((rows[0] as any)?.role ?? \"\").toLowerCase();\n return role === \"owner\" || role === \"admin\";\n } catch {\n return false;\n }\n}\n\nasync function resourceToAutomationItem(\n event: H3Event,\n userEmail: string,\n resource: Resource,\n): Promise<AutomationRouteItem> {\n const { meta, body } = parseTriggerFrontmatter(resource.content);\n return {\n id: resource.id,\n name: automationName(resource.path),\n path: resource.path,\n owner: resource.owner,\n canUpdate: await currentUserCanUpdateAutomation(\n event,\n userEmail,\n resource.owner,\n meta,\n ),\n triggerType: meta.triggerType,\n event: meta.event,\n schedule: meta.schedule || undefined,\n scheduleDescription: scheduleDescription(meta.schedule),\n condition: meta.condition,\n mode: meta.mode,\n domain: meta.domain,\n enabled: meta.enabled,\n lastStatus: meta.lastStatus,\n lastRun: meta.lastRun,\n lastError: meta.lastError,\n nextRun: nextRunForMeta(meta),\n createdBy: meta.createdBy,\n body,\n };\n}\n\nexport async function listAutomationsForOwner(\n event: H3Event,\n userEmail: string,\n): Promise<AutomationRouteItem[]> {\n const allResources = await resourceListAllOwners(\"jobs/\");\n const resources = allResources.filter(\n (resource) =>\n (resource.owner === userEmail || resource.owner === SHARED_OWNER) &&\n resource.path.endsWith(\".md\") &&\n !resource.path.endsWith(\".keep\"),\n );\n return Promise.all(\n resources.map((resource) =>\n resourceToAutomationItem(event, userEmail, resource),\n ),\n );\n}\n\nexport async function setAutomationEnabledForOwner(\n event: H3Event,\n userEmail: string,\n input: SetAutomationEnabledInput,\n): Promise<AutomationRouteItem> {\n if (typeof input.enabled !== \"boolean\") {\n throw Object.assign(new Error(\"enabled must be a boolean\"), {\n statusCode: 400,\n });\n }\n\n const path = normalizeAutomationPath(input);\n const requestedOwner =\n input.owner === SHARED_OWNER ? SHARED_OWNER : userEmail;\n const resource = await resourceGetByPath(requestedOwner, path);\n if (!resource) {\n throw Object.assign(new Error(\"Automation not found\"), { statusCode: 404 });\n }\n\n const { meta, body } = parseTriggerFrontmatter(resource.content);\n const allowed = await currentUserCanUpdateAutomation(\n event,\n userEmail,\n resource.owner,\n meta,\n );\n if (!allowed) {\n throw Object.assign(\n new Error(\"Only the automation creator or an org admin can update it.\"),\n { statusCode: 403 },\n );\n }\n\n meta.enabled = input.enabled;\n if (\n meta.enabled &&\n meta.triggerType !== \"event\" &&\n meta.schedule &&\n isValidCron(meta.schedule)\n ) {\n meta.nextRun = nextOccurrence(meta.schedule).toISOString();\n }\n\n await resourcePut(\n resource.owner,\n resource.path,\n buildTriggerContent(meta, body),\n );\n await refreshEventSubscriptions();\n\n return resourceToAutomationItem(event, userEmail, {\n ...resource,\n content: buildTriggerContent(meta, body),\n });\n}\n\nfunction routeError(event: H3Event, err: unknown, fallback: string) {\n const statusCode =\n typeof (err as any)?.statusCode === \"number\"\n ? (err as any).statusCode\n : 500;\n setResponseStatus(event, statusCode);\n return { error: (err as any)?.message ?? fallback };\n}\n\nexport function createAutomationsHandler() {\n return defineEventHandler(async (event: H3Event) => {\n const method = getMethod(event);\n const pathname = (event.path || event.url?.pathname || \"\")\n .split(\"?\")[0]\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Unauthenticated\" };\n }\n\n if (\n (pathname === \"fire-test\" || pathname.endsWith(\"/fire-test\")) &&\n method === \"POST\"\n ) {\n try {\n const { emit } = await import(\"../event-bus/index.js\");\n const body = (await readBody(event).catch(() => ({}))) as Record<\n string,\n unknown\n >;\n emit(\n \"test.event.fired\",\n { data: body.data ?? {} },\n { owner: session.email },\n );\n return { ok: true };\n } catch (err) {\n return routeError(event, err, \"Failed to emit test event\");\n }\n }\n\n if (method === \"GET\") {\n try {\n return await listAutomationsForOwner(event, session.email);\n } catch (err) {\n return routeError(event, err, \"Failed to list automations\");\n }\n }\n\n if (method === \"PATCH\" || method === \"PUT\") {\n try {\n const body = (await readBody(event).catch(\n () => ({}),\n )) as SetAutomationEnabledInput | null;\n return await setAutomationEnabledForOwner(event, session.email, {\n owner: body?.owner,\n path: body?.path,\n name: body?.name,\n enabled: (body as any)?.enabled,\n } as SetAutomationEnabledInput);\n } catch (err) {\n return routeError(event, err, \"Failed to update automation\");\n }\n }\n\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n });\n}\n"]}
|
package/docs/AGENTS.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Agent Native Docs For Agents
|
|
2
|
+
|
|
3
|
+
These docs are bundled with `@agent-native/core` and installed at:
|
|
4
|
+
|
|
5
|
+
```txt
|
|
6
|
+
node_modules/@agent-native/core/docs
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Use these version-matched markdown docs before coding against Agent Native
|
|
10
|
+
framework APIs or advanced features. Public docs are useful for browsing, but
|
|
11
|
+
the package docs match the exact framework version installed in the app.
|
|
12
|
+
|
|
13
|
+
## Fast Lookup
|
|
14
|
+
|
|
15
|
+
From a generated app root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm action docs-search --list
|
|
19
|
+
pnpm action docs-search --query "actions"
|
|
20
|
+
pnpm action docs-search --slug actions
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The built-in app agent also has a read-only `docs-search` tool with the same
|
|
24
|
+
`list`, `query`, and `slug` options.
|
|
25
|
+
|
|
26
|
+
If the action runner is unavailable, search the markdown files directly:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
rg -n "actions|automations|a2a|sharing" node_modules/@agent-native/core/docs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then read the matching files under `node_modules/@agent-native/core/docs/content/`.
|
|
33
|
+
|
|
34
|
+
## What To Read First
|
|
35
|
+
|
|
36
|
+
| Task | Start with |
|
|
37
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| Define or call app operations | `content/actions.md`, `content/client.md` |
|
|
39
|
+
| Add SQL data, schema, or access rules | `content/database.md`, `content/security.md`, `content/sharing.md` |
|
|
40
|
+
| Keep the UI and agent in sync | `content/context-awareness.md`, `content/client.md` |
|
|
41
|
+
| Build headless or chat-first apps | `content/pure-agent-apps.md`, `content/agent-surfaces.md`, `content/using-your-agent.md` |
|
|
42
|
+
| Add automations or scheduled work | `content/automations.md`, `content/recurring-jobs.md` |
|
|
43
|
+
| Compose apps or call sibling agents | `content/a2a-protocol.md`, `content/multi-app-workspace.md`, `content/workspace.md` |
|
|
44
|
+
| Expose tools to external agents | `content/external-agents.md`, `content/mcp-protocol.md`, `content/mcp-apps.md`, `content/mcp-clients.md` |
|
|
45
|
+
| Add integrations, setup, or secrets | `content/onboarding.md`, `content/workspace-connections.md`, `content/security.md` |
|
|
46
|
+
| Build extensions or custom widgets | `content/extensions.md`, `content/agent-web-surfaces.md` |
|
|
47
|
+
| Deploy or configure hosting | `content/deployment.md`, `content/server.md` |
|
|
48
|
+
| Write agent instructions or skills | `content/skills-guide.md`, `content/writing-agent-instructions.md` |
|
|
49
|
+
|
|
50
|
+
## Rules
|
|
51
|
+
|
|
52
|
+
- Prefer the app's own `AGENTS.md` and `.agents/skills/` for app-specific
|
|
53
|
+
behavior. Use this package docs tree for framework APIs and patterns.
|
|
54
|
+
- If local instructions and package docs conflict, local app instructions win
|
|
55
|
+
for that app, but verify the framework API shape in package docs or types.
|
|
56
|
+
- Do not invent Agent Native APIs. Search these docs and installed type
|
|
57
|
+
definitions before adding imports, routes, actions, or framework config.
|
package/docs/SKILL.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-native-docs
|
|
3
|
+
description: "How to look up version-matched Agent Native framework docs in node_modules. Use before coding against @agent-native/core APIs or advanced features."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Native Docs Lookup
|
|
7
|
+
|
|
8
|
+
## Rule
|
|
9
|
+
|
|
10
|
+
Before implementing non-trivial Agent Native functionality, read the
|
|
11
|
+
version-matched docs installed with `@agent-native/core`.
|
|
12
|
+
|
|
13
|
+
## How
|
|
14
|
+
|
|
15
|
+
1. Start from the generated app root.
|
|
16
|
+
2. Search with `pnpm action docs-search --query "<feature>"`.
|
|
17
|
+
3. Read a specific page with `pnpm action docs-search --slug <slug>`.
|
|
18
|
+
4. If the action runner is unavailable, search
|
|
19
|
+
`node_modules/@agent-native/core/docs` directly with `rg`.
|
|
20
|
+
5. For app-specific rules, also read the app's own `AGENTS.md` and any relevant
|
|
21
|
+
`.agents/skills/<name>/SKILL.md`.
|
|
22
|
+
|
|
23
|
+
## Useful Slugs
|
|
24
|
+
|
|
25
|
+
| Need | Slugs |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| Actions and typed client calls | `actions`, `client` |
|
|
28
|
+
| SQL, auth, access, sharing | `database`, `authentication`, `security`, `sharing` |
|
|
29
|
+
| UI state visible to the agent | `context-awareness` |
|
|
30
|
+
| Headless and chat-first apps | `pure-agent-apps`, `agent-surfaces`, `using-your-agent` |
|
|
31
|
+
| Automations and schedules | `automations`, `recurring-jobs` |
|
|
32
|
+
| Cross-app and external agents | `a2a-protocol`, `external-agents`, `mcp-protocol`, `mcp-apps` |
|
|
33
|
+
| Skills and instructions | `skills-guide`, `writing-agent-instructions` |
|
|
34
|
+
|
|
35
|
+
## Don't
|
|
36
|
+
|
|
37
|
+
- Do not rely on memory for framework APIs when local package docs are present.
|
|
38
|
+
- Do not add custom REST wrappers for normal app data before reading `actions`.
|
|
39
|
+
- Do not add inline LLM calls before reading `using-your-agent` and
|
|
40
|
+
`agent-surfaces`.
|
|
@@ -305,7 +305,7 @@ A mail agent needs analytics data. The analytics agent exposes a "run-query" ski
|
|
|
305
305
|
|
|
306
306
|
```ts
|
|
307
307
|
// In the mail agent's actions/get-analytics.ts
|
|
308
|
-
import { defineAction } from "@agent-native/core/
|
|
308
|
+
import { defineAction } from "@agent-native/core/action";
|
|
309
309
|
import { callAgent } from "@agent-native/core/a2a";
|
|
310
310
|
import { z } from "zod";
|
|
311
311
|
|
package/docs/content/actions.md
CHANGED
|
@@ -19,11 +19,51 @@ One definition, seven consumers. This is rung 3 of the [ladder](/docs/what-is-ag
|
|
|
19
19
|
If you are deciding whether to expose an operation headlessly, in chat, in an
|
|
20
20
|
embedded sidecar, or as a full app screen, see [Agent Surfaces](/docs/agent-surfaces).
|
|
21
21
|
|
|
22
|
+
## Start with one action {#hello-action}
|
|
23
|
+
|
|
24
|
+
The primitive-first on-ramp is one action, not a template. In a headless
|
|
25
|
+
scaffold such as `agent-native create my-agent --headless`, this can be the
|
|
26
|
+
whole first app:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// actions/hello.ts
|
|
30
|
+
import { defineAction } from "@agent-native/core/action";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
|
|
33
|
+
export default defineAction({
|
|
34
|
+
description: "Say hello from the local agent.",
|
|
35
|
+
schema: z.object({
|
|
36
|
+
name: z.string().default("world"),
|
|
37
|
+
}),
|
|
38
|
+
http: { method: "GET" },
|
|
39
|
+
readOnly: true,
|
|
40
|
+
run: async ({ name }) => {
|
|
41
|
+
return { message: `Hello, ${name}!` };
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Run it from the same folder:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm action hello --name Steve
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Then run the app-agent loop against the folder:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pnpm agent "Call hello for Steve and explain the result"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
That is the same app-agent loop your scheduled jobs, chat UI, external MCP
|
|
59
|
+
tools, and future screens will use. Chat and domain templates are for adding UI
|
|
60
|
+
around actions, not a required prerequisite for the action itself.
|
|
61
|
+
|
|
22
62
|
## Defining an action {#defining}
|
|
23
63
|
|
|
24
64
|
```ts
|
|
25
65
|
// actions/reply-to-email.ts
|
|
26
|
-
import { defineAction } from "@agent-native/core";
|
|
66
|
+
import { defineAction } from "@agent-native/core/action";
|
|
27
67
|
import { z } from "zod";
|
|
28
68
|
|
|
29
69
|
export default defineAction({
|
|
@@ -229,7 +269,7 @@ User-owned tables must scope reads through `accessFilter` and writes through `as
|
|
|
229
269
|
|
|
230
270
|
```ts
|
|
231
271
|
// actions/create-lead.ts
|
|
232
|
-
import { defineAction } from "@agent-native/core";
|
|
272
|
+
import { defineAction } from "@agent-native/core/action";
|
|
233
273
|
import { z } from "zod";
|
|
234
274
|
import { getDb } from "../server/db/index.js";
|
|
235
275
|
import * as schema from "../server/db/schema.js";
|
|
@@ -315,12 +355,12 @@ summaries, and insight cards; use [MCP Apps](/docs/mcp-apps) for inline UI in
|
|
|
315
355
|
external MCP hosts.
|
|
316
356
|
|
|
317
357
|
```ts
|
|
358
|
+
import { defineAction } from "@agent-native/core/action";
|
|
359
|
+
import { ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER } from "@agent-native/core/action-ui";
|
|
318
360
|
import {
|
|
319
|
-
|
|
361
|
+
createDataInsightsWidgetResult,
|
|
320
362
|
dataInsightsWidgetResultSchema,
|
|
321
|
-
|
|
322
|
-
} from "@agent-native/core";
|
|
323
|
-
import { createDataInsightsWidgetResult } from "@agent-native/core/data-widgets";
|
|
363
|
+
} from "@agent-native/core/data-widgets";
|
|
324
364
|
|
|
325
365
|
export default defineAction({
|
|
326
366
|
description: "Summarize response trends.",
|
|
@@ -411,7 +451,7 @@ Reads the current navigation state, fetches contextual data, and returns a snaps
|
|
|
411
451
|
|
|
412
452
|
```ts
|
|
413
453
|
// actions/view-screen.ts
|
|
414
|
-
import { defineAction } from "@agent-native/core";
|
|
454
|
+
import { defineAction } from "@agent-native/core/action";
|
|
415
455
|
import { readAppState } from "@agent-native/core/application-state";
|
|
416
456
|
import { z } from "zod";
|
|
417
457
|
|
|
@@ -438,7 +478,7 @@ Writes a one-shot navigation command to application state. The UI reads it, navi
|
|
|
438
478
|
|
|
439
479
|
```ts
|
|
440
480
|
// actions/navigate.ts
|
|
441
|
-
import { defineAction } from "@agent-native/core";
|
|
481
|
+
import { defineAction } from "@agent-native/core/action";
|
|
442
482
|
import { writeAppState } from "@agent-native/core/application-state";
|
|
443
483
|
import { z } from "zod";
|
|
444
484
|
|
|
@@ -13,13 +13,13 @@ application.
|
|
|
13
13
|
The useful way to choose is not by protocol first. Choose the product surface
|
|
14
14
|
you want, then use the matching primitive.
|
|
15
15
|
|
|
16
|
-
| Surface | Use it when | Start with
|
|
17
|
-
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
18
|
-
| **Headless agent/actions** | Code, jobs, scripts, another app, or another agent should call the work directly. | `defineAction`, HTTP, CLI, MCP, A2A
|
|
19
|
-
| **Rich chat on Agent-Native** | You want a standalone or embedded chat backed by the built-in agent loop. | `<AgentChatSurface>`, `<AssistantChat
|
|
20
|
-
| **Rich chat on your agent** | You built the agent elsewhere and want Agent-Native's composer, transcript, tool cards, and native widgets. | `AgentChatRuntime`, `<AssistantChat runtime={runtime}>`
|
|
21
|
-
| **Embedded sidecar** | You already have a SaaS app and want an agent beside it with page context and host commands. | `createAgentNativeEmbeddedPlugin()`, `AgentNativeEmbedded`
|
|
22
|
-
| **Full application** | Humans and agents should share durable screens, data, navigation, and collaboration. | Templates, actions, SQL state, context awareness
|
|
16
|
+
| Surface | Use it when | Start with |
|
|
17
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
18
|
+
| **Headless agent/actions** | Code, jobs, scripts, another app, or another agent should call the work directly. | `agent-native create --headless`, `defineAction`, `agent-native agent`, HTTP, CLI, MCP, A2A |
|
|
19
|
+
| **Rich chat on Agent-Native** | You want a standalone or embedded chat backed by the built-in agent loop. | [Chat template](/docs/template-chat), `<AgentChatSurface>`, `<AssistantChat>` |
|
|
20
|
+
| **Rich chat on your agent** | You built the agent elsewhere and want Agent-Native's composer, transcript, tool cards, and native widgets. | `AgentChatRuntime`, `<AssistantChat runtime={runtime}>` |
|
|
21
|
+
| **Embedded sidecar** | You already have a SaaS app and want an agent beside it with page context and host commands. | `createAgentNativeEmbeddedPlugin()`, `AgentNativeEmbedded` |
|
|
22
|
+
| **Full application** | Humans and agents should share durable screens, data, navigation, and collaboration. | Templates, actions, SQL state, context awareness |
|
|
23
23
|
|
|
24
24
|
Those are stages, not separate products. A workflow can start as a headless
|
|
25
25
|
action, appear in chat as a table or chart, and later become a full screen in an
|
|
@@ -31,11 +31,19 @@ Use the headless path when no one needs to stare at a custom app screen while
|
|
|
31
31
|
the work runs: scheduled jobs, integrations, backend workflows, CLI loops,
|
|
32
32
|
another agent, or an existing product calling into Agent-Native.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
The smallest local path is a headless scaffold plus one action:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @agent-native/core@latest create my-agent --headless
|
|
38
|
+
cd my-agent
|
|
39
|
+
pnpm install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then define the durable operation:
|
|
35
43
|
|
|
36
44
|
```ts
|
|
37
45
|
// actions/summarize-week.ts
|
|
38
|
-
import { defineAction } from "@agent-native/core";
|
|
46
|
+
import { defineAction } from "@agent-native/core/action";
|
|
39
47
|
import { z } from "zod";
|
|
40
48
|
|
|
41
49
|
export default defineAction({
|
|
@@ -52,14 +60,26 @@ One action is then callable as:
|
|
|
52
60
|
|
|
53
61
|
- **HTTP** — `POST /_agent-native/actions/summarize-week`
|
|
54
62
|
- **CLI** — `pnpm action summarize-week --formId form_123`
|
|
63
|
+
- **App-agent CLI** — `pnpm agent "Summarize form_123"`
|
|
55
64
|
- **MCP** — from Claude, ChatGPT, Codex, Cursor, OpenCode, Copilot, and other MCP hosts
|
|
56
65
|
- **A2A** — from another agent-native app or agent peer
|
|
57
66
|
- **UI** — through `useActionQuery`, `useActionMutation`, or `callAction`
|
|
58
67
|
- **Agent tool** — from the built-in chat loop
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
This is not a no-database or stateless mode. The app-agent loop stores sessions,
|
|
70
|
+
threads, runs, settings, credentials, application state, and share records in
|
|
71
|
+
SQL. Local development defaults to SQLite; hosted headless apps should use a
|
|
72
|
+
persistent SQL database.
|
|
73
|
+
|
|
74
|
+
If you need the whole agent loop headlessly from the project folder, use:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pnpm agent "Summarize this week's forms."
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Workers, jobs, integration webhooks, and custom hosts can use the server API
|
|
81
|
+
directly. This is lower-level than actions: you provide the engine, model,
|
|
82
|
+
messages, actions, and event sink yourself.
|
|
63
83
|
|
|
64
84
|
```ts
|
|
65
85
|
import {
|
|
@@ -97,11 +117,49 @@ For most apps, scheduled prompts and integration webhooks already call this loop
|
|
|
97
117
|
for you. Reach for direct `runAgentLoop()` when you are building a custom
|
|
98
118
|
headless host, eval runner, or server-side orchestration surface.
|
|
99
119
|
|
|
120
|
+
### Running against a folder {#folder-loop}
|
|
121
|
+
|
|
122
|
+
If your goal is "run an agent against this folder," start with the app-agent
|
|
123
|
+
loop in that folder: scaffold the headless app, add actions/instructions, run
|
|
124
|
+
`pnpm agent "..."`. That keeps the work inside the same action/runtime/state
|
|
125
|
+
contract the app will use in production.
|
|
126
|
+
|
|
127
|
+
External coding harnesses are a separate product surface for embedding Claude
|
|
128
|
+
Code, Codex, Pi, Cursor, Mastra, or similar runtimes inside an Agent-Native app.
|
|
129
|
+
Use them when you are building a coding-agent product, not as the default way to
|
|
130
|
+
start a local agent-native workflow.
|
|
131
|
+
|
|
132
|
+
### Cloud repo access {#cloud-repo-access}
|
|
133
|
+
|
|
134
|
+
For cloud headless apps that need repository access, the planned model is a
|
|
135
|
+
GitHub connector plus token CRUD: list repositories, search files, read files,
|
|
136
|
+
create or edit files, delete files, and revoke access through provider-scoped
|
|
137
|
+
credentials.
|
|
138
|
+
|
|
139
|
+
Do not treat a VM clone or long-lived sandbox checkout as the primary cloud
|
|
140
|
+
repo-access model. Sandboxes still matter for isolated code execution, but
|
|
141
|
+
repository access should be explicit, permissioned, auditable, and revocable
|
|
142
|
+
through the connector layer.
|
|
143
|
+
|
|
144
|
+
### Sharing sessions and runs {#sharing-runs}
|
|
145
|
+
|
|
146
|
+
Headless sessions and runs are durable objects. Shareability should be phased:
|
|
147
|
+
read/share links first, so teammates can inspect sanitized prompts, outputs,
|
|
148
|
+
and run status; permissioned writable collaboration later, so continuing a run,
|
|
149
|
+
approving actions, editing schedules, or changing configuration goes through
|
|
150
|
+
explicit access checks.
|
|
151
|
+
|
|
100
152
|
## Rich chat on Agent-Native {#rich-chat}
|
|
101
153
|
|
|
102
154
|
Use the built-in chat when the user should talk to the agent, see tool calls,
|
|
103
155
|
approve work, inspect native results, and keep a durable thread history.
|
|
104
156
|
|
|
157
|
+
For a full app starting point, use the [Chat template](/docs/template-chat):
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npx @agent-native/core@latest create my-chat-app --template chat
|
|
161
|
+
```
|
|
162
|
+
|
|
105
163
|
The simplest full-page chat:
|
|
106
164
|
|
|
107
165
|
```tsx
|
|
@@ -131,6 +189,9 @@ components in the chat, without iframes. See [Native Chat UI](/docs/native-chat-
|
|
|
131
189
|
Use this path when your agent is already built with another framework or
|
|
132
190
|
runtime and you want Agent-Native's chat UI around it.
|
|
133
191
|
|
|
192
|
+
The [Chat template](/docs/template-chat) is still useful here: keep its app
|
|
193
|
+
shell and thread UI, then swap the runtime behind the chat plugin or route.
|
|
194
|
+
|
|
134
195
|
`AgentChatRuntime` is the boundary. Your runtime streams normalized events;
|
|
135
196
|
Agent-Native renders the composer, transcript, tool calls, approvals, native
|
|
136
197
|
widgets, and app layout.
|
|
@@ -245,8 +306,9 @@ Full apps add product UI around the same action and agent contract:
|
|
|
245
306
|
- **Deep links** — action results can open the right app view.
|
|
246
307
|
- **Native chat widgets** — tables, charts, cards, approvals, and typed results appear inline.
|
|
247
308
|
|
|
248
|
-
Start from
|
|
249
|
-
from [
|
|
309
|
+
Start from the [Chat template](/docs/template-chat) when you want a minimal app
|
|
310
|
+
around your actions, or from a domain [template](/docs/cloneable-saas) when you
|
|
311
|
+
want a complete product shape.
|
|
250
312
|
|
|
251
313
|
## How to choose {#how-to-choose}
|
|
252
314
|
|
|
@@ -228,7 +228,7 @@ Actions can use CLI adapters directly for structured access:
|
|
|
228
228
|
|
|
229
229
|
```ts
|
|
230
230
|
// actions/list-prs.ts
|
|
231
|
-
import { defineAction } from "@agent-native/core/
|
|
231
|
+
import { defineAction } from "@agent-native/core/action";
|
|
232
232
|
import { ShellCliAdapter } from "@agent-native/core/adapters/cli";
|
|
233
233
|
import { z } from "zod";
|
|
234
234
|
|
|
@@ -15,6 +15,7 @@ Each one is a real app you could use today, and the launching pad for your own v
|
|
|
15
15
|
|
|
16
16
|
| Template | What it is |
|
|
17
17
|
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| [**Chat**](/docs/template-chat) | Minimal chat-first app with durable threads, actions, auth, and a clean path to custom UI or your own backend. |
|
|
18
19
|
| [**Mail**](/docs/template-mail) | An agent-native Superhuman. Inbox, labels, AI triage, keyboard-first, drafts and sends through the agent. |
|
|
19
20
|
| [**Calendar**](/docs/template-calendar) | An agent-native Google Calendar. Events, sync, public booking links, agent-driven scheduling. |
|
|
20
21
|
| [**Content**](/docs/template-content) | Open-source Obsidian for MDX. Local Markdown/MDX, Tiptap editor, Notion sync, real-time multi-user collab. |
|
|
@@ -29,7 +30,7 @@ Each one is a real app you could use today, and the launching pad for your own v
|
|
|
29
30
|
| [**Plan**](/docs/template-plan) | Visual plans and PR recaps with diagrams, wireframes, and annotations. |
|
|
30
31
|
| [**Dispatch**](/docs/template-dispatch) | The workspace control plane: shared secrets, reusable integrations, Slack/Telegram, scheduled jobs. |
|
|
31
32
|
|
|
32
|
-
Don't want a domain template?
|
|
33
|
+
Don't want a domain template? Use [Chat](/docs/template-chat) when you want a basic app users can talk to immediately, or start action-first with [Pure-Agent Apps](/docs/pure-agent-apps).
|
|
33
34
|
|
|
34
35
|
See the full catalog under [Templates](/templates), or jump straight to one — for example, [Dispatch](/docs/template-dispatch) is a great place to start if you want a workspace-style app.
|
|
35
36
|
|
|
@@ -72,11 +73,11 @@ You don't have to. Every template is also available as a hosted app on `agent-na
|
|
|
72
73
|
|
|
73
74
|
## Try it with a skill {#try-with-a-skill}
|
|
74
75
|
|
|
75
|
-
Not ready to scaffold? You can add agent-native superpowers to a coding agent you already use with a single command — no app needed. See [
|
|
76
|
+
Not ready to scaffold? You can add agent-native superpowers to a coding agent you already use with a single command — no app needed. See the [Skills Guide](/docs/skills-guide#app-backed-skills).
|
|
76
77
|
|
|
77
78
|
## Building on this
|
|
78
79
|
|
|
79
|
-
- [**Getting Started**](/docs/getting-started) —
|
|
80
|
+
- [**Getting Started**](/docs/getting-started) — create a minimal chat app or headless action
|
|
80
81
|
- [**Messaging the agent**](/docs/messaging) — how users (and you) talk to the agent that ships with each template
|
|
81
82
|
- [**Multi-App Workspace**](/docs/multi-app-workspace) — bundle several templates into one workspace that shares auth, brand, and agent
|
|
82
83
|
- [**Dispatch**](/docs/template-dispatch) — the workspace control plane template
|
|
@@ -90,7 +91,7 @@ If you're scaffolding now, the CLI command is:
|
|
|
90
91
|
npx @agent-native/core@latest create my-platform
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
You'll get a multi-select picker. Pick one app (standalone) or several (workspace — apps share auth, brand, agent config, and database). Each picked template is scaffolded into `apps/<name>/` with every file you need.
|
|
94
|
+
You'll get a multi-select picker. Pick one app (standalone) or several (workspace — apps share auth, brand, agent config, and database). Each picked template is scaffolded into `apps/<name>/` with every file you need. For an action-only app instead of a template UI, use `npx @agent-native/core@latest create my-agent --headless`.
|
|
94
95
|
|
|
95
96
|
Fill in `.env` (mostly `ANTHROPIC_API_KEY` and `DATABASE_URL`), `pnpm install`, `pnpm dev`, and it works. No "TODO: implement login," no placeholder routes.
|
|
96
97
|
|