@agent-native/core 0.210.0-nightly-20261019183757 → 0.210.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.
Files changed (35) hide show
  1. package/dist/agent/action-error-details.d.ts +26 -0
  2. package/dist/agent/action-error-details.js +99 -0
  3. package/dist/agent/production-agent.js +9 -0
  4. package/dist/agent/tool-error-redaction.d.ts +8 -1
  5. package/dist/agent/tool-error-redaction.js +70 -7
  6. package/dist/automation/index.d.ts +1 -1
  7. package/dist/collab/awareness.d.ts +2 -2
  8. package/dist/collab/routes.d.ts +1 -1
  9. package/dist/collab/struct-routes.d.ts +1 -1
  10. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  11. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  12. package/dist/mcp/direct-action-call.js +39 -10
  13. package/dist/notifications/routes.d.ts +3 -3
  14. package/dist/observability/routes.d.ts +7 -7
  15. package/dist/progress/routes.d.ts +1 -1
  16. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  17. package/dist/secrets/routes.d.ts +10 -10
  18. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  19. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  20. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  21. package/dist/server/realtime-token.d.ts +1 -1
  22. package/dist/server/transcribe-voice.d.ts +1 -1
  23. package/dist/templates/chat/.agents/skills/actions/SKILL.md +2 -2
  24. package/dist/templates/default/.agents/skills/actions/SKILL.md +2 -2
  25. package/dist/templates/factory/.agents/skills/review-prs/SKILL.md +44 -21
  26. package/dist/templates/headless/.agents/skills/actions/SKILL.md +2 -2
  27. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +2 -2
  28. package/dist/triggers/actions/manage-automation.d.ts +5 -5
  29. package/docs/content/actions-defining.mdx +2 -2
  30. package/package.json +4 -4
  31. package/src/templates/chat/.agents/skills/actions/SKILL.md +2 -2
  32. package/src/templates/default/.agents/skills/actions/SKILL.md +2 -2
  33. package/src/templates/factory/.agents/skills/review-prs/SKILL.md +44 -21
  34. package/src/templates/headless/.agents/skills/actions/SKILL.md +2 -2
  35. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +2 -2
@@ -0,0 +1,26 @@
1
+ /** Longest serialized `details` an agent sees with a failed action. */
2
+ export declare const MAX_AGENT_ERROR_DETAILS_CHARS = 2000;
3
+ export interface AgentErrorDetails {
4
+ /** The `details` a `fail()` attached, as the browser receives them, redacted and bounded. */
5
+ details: Record<string, unknown>;
6
+ /**
7
+ * Top-level keys left out to stay within the bound, or because they don't
8
+ * serialize: up to ten names, each clipped, with the full count beside them.
9
+ */
10
+ omittedKeys?: string[];
11
+ omittedKeyCount?: number;
12
+ /** The line a text-only tool result carries, so text clients see the same data. */
13
+ line: string;
14
+ }
15
+ /**
16
+ * The structured `details` of a failed action, in the form an agent reads.
17
+ *
18
+ * Only a contract error (`fail()`) carries details meant for the caller; the
19
+ * HTTP action route already returns them to the browser, so an agent acting
20
+ * for the same user gets the same object. Values go through a JSON round trip
21
+ * first, so a `Date` reads as the browser would see it rather than as `{}`.
22
+ * When the whole object is too long, small top-level entries are kept in
23
+ * order and the rest are named in `omittedKeys`: a retry id must survive next
24
+ * to a large payload, and a cut must never read as a complete object.
25
+ */
26
+ export declare function agentErrorDetails(error: unknown): AgentErrorDetails | undefined;
@@ -0,0 +1,99 @@
1
+ import { isActionContractError } from "../action.js";
2
+ import { redactSensitiveFields, sanitizeToolErrorText, } from "./tool-error-redaction.js";
3
+ /** Longest serialized `details` an agent sees with a failed action. */
4
+ export const MAX_AGENT_ERROR_DETAILS_CHARS = 2_000;
5
+ /** A top-level entry longer than this is left out once the whole set is too long. */
6
+ const MAX_KEPT_ENTRY_CHARS = 300;
7
+ const MAX_LISTED_OMITTED_KEYS = 10;
8
+ const MAX_OMITTED_KEY_CHARS = 60;
9
+ /**
10
+ * The structured `details` of a failed action, in the form an agent reads.
11
+ *
12
+ * Only a contract error (`fail()`) carries details meant for the caller; the
13
+ * HTTP action route already returns them to the browser, so an agent acting
14
+ * for the same user gets the same object. Values go through a JSON round trip
15
+ * first, so a `Date` reads as the browser would see it rather than as `{}`.
16
+ * When the whole object is too long, small top-level entries are kept in
17
+ * order and the rest are named in `omittedKeys`: a retry id must survive next
18
+ * to a large payload, and a cut must never read as a complete object.
19
+ */
20
+ export function agentErrorDetails(error) {
21
+ if (!isActionContractError(error))
22
+ return undefined;
23
+ const raw = error.details;
24
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
25
+ return undefined;
26
+ const entries = [];
27
+ const omittedKeys = [];
28
+ for (const key of Object.keys(raw)) {
29
+ const clean = jsonSafeEntry(raw, key);
30
+ if (clean === UNSERIALIZABLE)
31
+ omittedKeys.push(key);
32
+ else if (clean !== undefined)
33
+ entries.push([key, clean]);
34
+ }
35
+ const cleaned = Object.fromEntries(entries);
36
+ let details = cleaned;
37
+ if (JSON.stringify(cleaned).length > MAX_AGENT_ERROR_DETAILS_CHARS) {
38
+ details = {};
39
+ let budget = MAX_AGENT_ERROR_DETAILS_CHARS - 2;
40
+ for (const [key, value] of entries) {
41
+ const size = JSON.stringify({ [key]: value }).length - 1;
42
+ if (size <= MAX_KEPT_ENTRY_CHARS && size <= budget) {
43
+ details[key] = value;
44
+ budget -= size;
45
+ }
46
+ else {
47
+ omittedKeys.push(key);
48
+ }
49
+ }
50
+ }
51
+ if (Object.keys(details).length === 0 && omittedKeys.length === 0) {
52
+ return undefined;
53
+ }
54
+ const listed = omittedKeys
55
+ .slice(0, MAX_LISTED_OMITTED_KEYS)
56
+ .map((key) => key.length > MAX_OMITTED_KEY_CHARS
57
+ ? `${key.slice(0, MAX_OMITTED_KEY_CHARS)}…`
58
+ : key);
59
+ const more = omittedKeys.length > listed.length
60
+ ? `, and ${omittedKeys.length - listed.length} more`
61
+ : "";
62
+ return {
63
+ details,
64
+ ...(omittedKeys.length > 0
65
+ ? { omittedKeys: listed, omittedKeyCount: omittedKeys.length }
66
+ : {}),
67
+ line: `Error details${listed.length > 0 ? ` (omitted: ${listed.join(", ")}${more})` : ""}: ${JSON.stringify(details)}`,
68
+ };
69
+ }
70
+ const UNSERIALIZABLE = Symbol("unserializable");
71
+ function jsonSafeEntry(raw, key) {
72
+ let parsed;
73
+ try {
74
+ // A getter can throw. Reading it here names the key; reading it outside
75
+ // would replace the action's own error.
76
+ const json = JSON.stringify(raw[key]);
77
+ if (json === undefined)
78
+ return undefined;
79
+ parsed = JSON.parse(json);
80
+ }
81
+ catch {
82
+ return UNSERIALIZABLE;
83
+ }
84
+ const redacted = redactSensitiveFields({ [key]: parsed }, { compoundNames: true });
85
+ return sanitizeStrings(redacted[key]);
86
+ }
87
+ function sanitizeStrings(value) {
88
+ if (typeof value === "string")
89
+ return sanitizeToolErrorText(value);
90
+ if (Array.isArray(value))
91
+ return value.map(sanitizeStrings);
92
+ if (value && typeof value === "object") {
93
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
94
+ key,
95
+ sanitizeStrings(entry),
96
+ ]));
97
+ }
98
+ return value;
99
+ }
@@ -56,6 +56,7 @@ import { DurableAttachmentReferenceRequiredError, stripInlineBytes, } from "../s
56
56
  import { isReasoningEffort, normalizeReasoningEffortForRequest, stepDownReasoningEffort, } from "../shared/reasoning-effort.js";
57
57
  import { SYNTHETIC_TRAFFIC_BETA_E2E, SYNTHETIC_TRAFFIC_HEADER, } from "../shared/test-traffic.js";
58
58
  import { actionPreparationContinuationNote } from "./action-continuation-guidance.js";
59
+ import { agentErrorDetails } from "./action-error-details.js";
59
60
  import { drainAgentWarnings, formatAgentWarningsForToolResult, } from "./action-warnings.js";
60
61
  import { approvalKeyWithArguments } from "./approval-key.js";
61
62
  import { CONTINUE_UNAVAILABLE_CODE, } from "./auto-continue.js";
@@ -6617,6 +6618,7 @@ export async function runAgentLoop(opts) {
6617
6618
  // handler returned does not.
6618
6619
  let toolResultLost = false;
6619
6620
  let toolErrorCode;
6621
+ let toolErrorDetailsLine = "";
6620
6622
  let mcpApp;
6621
6623
  let toolResultImages;
6622
6624
  let toolArtifacts = [];
@@ -6928,6 +6930,7 @@ export async function runAgentLoop(opts) {
6928
6930
  toolErrorCode = isActionContractError(err)
6929
6931
  ? err.errorCode
6930
6932
  : undefined;
6933
+ toolErrorDetailsLine = agentErrorDetails(err)?.line ?? "";
6931
6934
  result = signal.aborted
6932
6935
  ? INTERRUPTED_TOOL_RESULT_MARKER
6933
6936
  : thrownToolResult(err);
@@ -6940,7 +6943,13 @@ export async function runAgentLoop(opts) {
6940
6943
  if (isError) {
6941
6944
  receipt = undefined;
6942
6945
  if (result !== INTERRUPTED_TOOL_RESULT_MARKER) {
6946
+ // Details go on after the loop breakers and the precondition
6947
+ // stop read the result: a retry id that changes on every attempt
6948
+ // must not make the same failure look like a new one.
6943
6949
  result = finalizeToolErrorResult(result);
6950
+ if (toolErrorDetailsLine) {
6951
+ result = `${result}\n${toolErrorDetailsLine}`;
6952
+ }
6944
6953
  }
6945
6954
  }
6946
6955
  else {
@@ -1,3 +1,10 @@
1
- export declare function redactSensitiveFields(value: unknown): unknown;
1
+ /**
2
+ * `compoundNames` also redacts names such as `clientSecret`, `x-api-key`,
3
+ * `githubToken` or `embedTicket`.
4
+ * Tool-error text leaves it off and keeps names like `mySecret` readable.
5
+ */
6
+ export declare function redactSensitiveFields(value: unknown, options?: {
7
+ compoundNames?: boolean;
8
+ }): unknown;
2
9
  export declare function sanitizeToolErrorText(value: string): string;
3
10
  export declare function sanitizeToolErrorValue(value: unknown): string;
@@ -1,22 +1,85 @@
1
+ import { EMBED_RESULT_SENSITIVE_KEYS } from "../mcp/embed-redaction.js";
1
2
  const REDACTED = "[REDACTED]";
2
3
  const SENSITIVE_FIELD_PATTERN = /^(authorization|cookie|api[_-]?key|password|secret|token|access[_-]?token|refresh[_-]?token|bearer)$/i;
4
+ // Only the trailing words of a compound name count. A `…Token` is a
5
+ // credential unless it is a cursor such as `nextPageToken`, which an agent
6
+ // needs for a retry. A `…Ticket` can redeem an embed session.
7
+ const SENSITIVE_LAST_WORDS = new Set([
8
+ "authorization",
9
+ "cookie",
10
+ "credential",
11
+ "credentials",
12
+ "passphrase",
13
+ "password",
14
+ "secret",
15
+ "secrets",
16
+ "ticket",
17
+ ]);
18
+ const SENSITIVE_LAST_WORD_PAIRS = new Set([
19
+ "access key",
20
+ "api key",
21
+ "private key",
22
+ "secret key",
23
+ ]);
24
+ const CURSOR_TOKEN_QUALIFIERS = new Set([
25
+ "continuation",
26
+ "cursor",
27
+ "delta",
28
+ "idempotency",
29
+ "next",
30
+ "page",
31
+ "prev",
32
+ "previous",
33
+ "resume",
34
+ "skip",
35
+ "sync",
36
+ ]);
37
+ function isSensitiveCompoundFieldName(key) {
38
+ if (SENSITIVE_FIELD_PATTERN.test(key) ||
39
+ EMBED_RESULT_SENSITIVE_KEYS.has(key)) {
40
+ return true;
41
+ }
42
+ const words = key
43
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
44
+ .toLowerCase()
45
+ .split(/[^a-z0-9]+/)
46
+ .filter(Boolean);
47
+ const last = words.at(-1);
48
+ if (!last)
49
+ return false;
50
+ if (SENSITIVE_LAST_WORDS.has(last))
51
+ return true;
52
+ if (last === "token") {
53
+ return words.length > 1 && !CURSOR_TOKEN_QUALIFIERS.has(words.at(-2));
54
+ }
55
+ return (words.length > 1 && SENSITIVE_LAST_WORD_PAIRS.has(`${words.at(-2)} ${last}`));
56
+ }
3
57
  const OPENAI_LIKE_SECRET_PATTERN = /(^|[^A-Za-z0-9_-])(sk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{24,})(?=$|[^A-Za-z0-9_-])/g;
4
- export function redactSensitiveFields(value) {
5
- return redactWalk(value, new WeakSet());
58
+ /**
59
+ * `compoundNames` also redacts names such as `clientSecret`, `x-api-key`,
60
+ * `githubToken` or `embedTicket`.
61
+ * Tool-error text leaves it off and keeps names like `mySecret` readable.
62
+ */
63
+ export function redactSensitiveFields(value, options = {}) {
64
+ const isSensitive = options.compoundNames
65
+ ? isSensitiveCompoundFieldName
66
+ : (key) => SENSITIVE_FIELD_PATTERN.test(key);
67
+ return redactWalk(value, new WeakSet(), isSensitive);
6
68
  }
7
- function redactWalk(value, seen) {
69
+ function redactWalk(value, seen, isSensitive) {
8
70
  if (value === null || typeof value !== "object")
9
71
  return value;
10
72
  if (seen.has(value))
11
73
  return "[Circular]";
12
74
  seen.add(value);
13
- if (Array.isArray(value))
14
- return value.map((v) => redactWalk(v, seen));
75
+ if (Array.isArray(value)) {
76
+ return value.map((v) => redactWalk(v, seen, isSensitive));
77
+ }
15
78
  const out = {};
16
79
  for (const [key, entry] of Object.entries(value)) {
17
- out[key] = SENSITIVE_FIELD_PATTERN.test(key)
80
+ out[key] = isSensitive(key)
18
81
  ? REDACTED
19
- : redactWalk(entry, seen);
82
+ : redactWalk(entry, seen, isSensitive);
20
83
  }
21
84
  return out;
22
85
  }
@@ -139,8 +139,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
139
139
  duplicate?: undefined;
140
140
  eventId?: undefined;
141
141
  } | {
142
+ error?: undefined;
142
143
  accepted: boolean;
143
144
  duplicate: boolean;
144
145
  eventId: string;
145
- error?: undefined;
146
146
  }>;
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
+ error?: undefined;
41
42
  states: {
42
43
  clientId: number;
43
44
  state: string;
44
45
  }[];
45
- error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
+ error?: undefined;
51
52
  users: {
52
53
  clientId: number;
53
54
  lastSeen: number;
54
55
  }[];
55
- error?: undefined;
56
56
  }>>;
@@ -21,8 +21,8 @@ export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import
21
21
  }>>;
22
22
  export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
23
23
  ok?: undefined;
24
- error: string;
25
24
  text?: undefined;
25
+ error: string;
26
26
  } | {
27
27
  error?: undefined;
28
28
  ok: boolean;
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- error: string;
3
2
  ok?: undefined;
3
+ error: string;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -42,8 +42,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
42
42
  url: string;
43
43
  id: string;
44
44
  provider: string;
45
- configured?: undefined;
46
45
  error?: undefined;
46
+ configured?: undefined;
47
47
  } | {
48
48
  url?: undefined;
49
49
  id?: undefined;
@@ -11,9 +11,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
11
11
  enabled?: undefined;
12
12
  nextRun?: undefined;
13
13
  } | {
14
+ deleted?: undefined;
14
15
  name: string;
15
16
  enabled: boolean;
16
17
  nextRun: string;
17
- deleted?: undefined;
18
18
  }>;
19
19
  export default _default;
@@ -1,5 +1,6 @@
1
1
  import { actionCallReadOnly, actionChangeResource, } from "../action-call-classification.js";
2
2
  import { ActionOutputContractError, failedCallEmitsChange, isActionOutputContractError, invocationEffect, ranCallEmitsChange, } from "../action.js";
3
+ import { agentErrorDetails } from "../agent/action-error-details.js";
3
4
  import { extractAgentImagesFromActionResult } from "../agent/tool-result-images.js";
4
5
  import { writeActionChangeMarker } from "../server/action-change-marker-write.js";
5
6
  import { captureError } from "../server/capture-error.js";
@@ -35,6 +36,13 @@ export function createDirectActionCall(scope) {
35
36
  return async (call, fail) => {
36
37
  const { name, args, request, ctx } = call;
37
38
  const callableActions = fullCatalogRequested ? actions : advertisedActions;
39
+ // A directory profile may project results arbitrarily, so the derived
40
+ // contract is advertised and enforced on app catalogs only. It compiles
41
+ // before the action runs. A host may hold an error result to the same
42
+ // schema, so a contracted tool's errors carry no structuredContent.
43
+ const outputContract = directoryCatalog
44
+ ? undefined
45
+ : callableActions[name]?.mcpOutputContract;
38
46
  const errorText = (err) => {
39
47
  const projectedError = directoryCatalog && config.directoryProfile?.projectResult
40
48
  ? config.directoryProfile.projectResult(name, err.message)
@@ -55,10 +63,37 @@ export function createDirectActionCall(scope) {
55
63
  try {
56
64
  const errorCode = mcpActionErrorCode(err);
57
65
  const { errorType, errorMessage } = describeMcpError(err);
58
- return toolCallError({
59
- errorType: redactEmbedText(errorType),
60
- errorMessage: redactEmbedText(errorMessage),
61
- }, `${redactEmbedText(errorText(err))}${errorCode !== undefined ? ` (errorCode: ${redactEmbedText(errorCode)})` : ""}`);
66
+ const message = redactEmbedText(errorText(err));
67
+ // A directory profile decides what its catalog shows, and it
68
+ // projects only the message.
69
+ const details = directoryCatalog ? undefined : agentErrorDetails(err);
70
+ const detailsLine = details && redactEmbedText(details.line);
71
+ return {
72
+ ...toolCallError({
73
+ errorType: redactEmbedText(errorType),
74
+ errorMessage: redactEmbedText(errorMessage),
75
+ }, `${message}${errorCode !== undefined ? ` (errorCode: ${redactEmbedText(errorCode)})` : ""}${detailsLine ? `\n${detailsLine}` : ""}`),
76
+ // Some clients hand the model structuredContent in place of the
77
+ // text, so it repeats the message rather than carrying details
78
+ // alone. Details the embed check hid in the text stay out of it.
79
+ ...(details && detailsLine === details.line && !outputContract
80
+ ? {
81
+ structuredContent: {
82
+ error: {
83
+ message,
84
+ errorCode: err.errorCode,
85
+ details: details.details,
86
+ ...(details.omittedKeys
87
+ ? {
88
+ omittedKeys: details.omittedKeys,
89
+ omittedKeyCount: details.omittedKeyCount,
90
+ }
91
+ : {}),
92
+ },
93
+ },
94
+ }
95
+ : {}),
96
+ };
62
97
  }
63
98
  catch {
64
99
  return toolCallError({
@@ -67,12 +102,6 @@ export function createDirectActionCall(scope) {
67
102
  });
68
103
  }
69
104
  };
70
- // A directory profile may project results arbitrarily, so the derived
71
- // contract is advertised and enforced on app catalogs only. It compiles
72
- // before the action runs.
73
- const outputContract = directoryCatalog
74
- ? undefined
75
- : callableActions[name]?.mcpOutputContract;
76
105
  let checkOutput;
77
106
  try {
78
107
  checkOutput = outputContract
@@ -1,12 +1,12 @@
1
1
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
2
+ error?: undefined;
2
3
  count: number;
3
4
  updated?: undefined;
4
- error?: undefined;
5
5
  ok?: undefined;
6
6
  } | {
7
+ error?: undefined;
7
8
  count?: undefined;
8
9
  updated: number;
9
- error?: undefined;
10
10
  ok?: undefined;
11
11
  } | {
12
12
  count?: undefined;
@@ -14,8 +14,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
14
14
  error: string;
15
15
  ok?: undefined;
16
16
  } | {
17
+ error?: undefined;
17
18
  count?: undefined;
18
19
  updated?: undefined;
19
- error?: undefined;
20
20
  ok: boolean;
21
21
  }>>;
@@ -27,43 +27,43 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
27
27
  thumbsUpRate: number;
28
28
  avgEvalScore: number;
29
29
  } | {
30
+ ok?: undefined;
30
31
  error: string;
31
32
  message: string;
32
33
  summary?: undefined;
33
34
  spans?: undefined;
34
- ok?: undefined;
35
35
  } | {
36
+ error?: undefined;
37
+ ok?: undefined;
36
38
  message?: undefined;
37
39
  summary: import("./types.js").TraceSummary;
38
40
  spans: import("./types.js").TraceSpan[];
41
+ } | {
39
42
  error?: undefined;
40
43
  ok?: undefined;
41
- } | {
42
44
  message?: undefined;
43
45
  summary?: undefined;
44
46
  spans?: undefined;
45
47
  traceMissing: true;
46
48
  id: string;
49
+ } | {
47
50
  error?: undefined;
48
51
  ok?: undefined;
49
- } | {
50
52
  message?: undefined;
51
53
  summary?: undefined;
52
54
  spans?: undefined;
53
55
  traceMissing?: undefined;
54
56
  id: string;
55
- error?: undefined;
56
- ok?: undefined;
57
57
  } | {
58
+ ok?: undefined;
58
59
  message?: undefined;
59
60
  summary?: undefined;
60
61
  spans?: undefined;
61
62
  error: any;
62
- ok?: undefined;
63
63
  } | {
64
+ error?: undefined;
64
65
  message?: undefined;
65
66
  summary?: undefined;
66
67
  spans?: undefined;
67
- error?: undefined;
68
68
  ok: boolean;
69
69
  }>>;
@@ -2,6 +2,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
2
2
  error: string;
3
3
  ok?: undefined;
4
4
  } | {
5
- ok: boolean;
6
5
  error?: undefined;
6
+ ok: boolean;
7
7
  }>>;
@@ -75,6 +75,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
75
75
  user: "user";
76
76
  }>>;
77
77
  }, z.core.$strip>>, {
78
+ message?: undefined;
78
79
  deleted?: undefined;
79
80
  found?: undefined;
80
81
  id?: undefined;
@@ -91,8 +92,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
91
92
  provider?: undefined;
92
93
  registered?: undefined;
93
94
  label?: undefined;
94
- message?: undefined;
95
95
  } | {
96
+ message?: undefined;
96
97
  deleted?: undefined;
97
98
  id?: undefined;
98
99
  providers?: undefined;
@@ -101,8 +102,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
101
102
  provider: import("../custom-registry.js").CustomProviderConfig;
102
103
  registered?: 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;
@@ -57,39 +57,39 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
57
57
  } | {
58
58
  error: string;
59
59
  errorCode?: undefined;
60
- status?: undefined;
61
60
  ok?: undefined;
61
+ status?: undefined;
62
62
  } | {
63
63
  error: string;
64
64
  errorCode: string;
65
- status?: undefined;
66
65
  ok?: undefined;
66
+ status?: undefined;
67
67
  } | {
68
+ error?: undefined;
68
69
  errorCode?: undefined;
69
70
  ok: boolean;
70
71
  status: string;
71
- error?: undefined;
72
72
  } | {
73
+ ok?: undefined;
73
74
  error: string;
74
75
  removed?: undefined;
75
- ok?: undefined;
76
76
  } | {
77
+ error?: undefined;
77
78
  ok: boolean;
78
79
  removed: boolean;
79
- error?: undefined;
80
80
  }>>;
81
81
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
82
+ ok?: undefined;
82
83
  error: string;
83
84
  note?: undefined;
84
- ok?: undefined;
85
85
  } | {
86
+ error?: undefined;
86
87
  ok: boolean;
87
88
  note?: undefined;
88
- error?: undefined;
89
89
  } | {
90
+ error?: undefined;
90
91
  ok: boolean;
91
92
  note: string;
92
- error?: undefined;
93
93
  } | {
94
94
  note?: undefined;
95
95
  ok: boolean;
@@ -117,11 +117,11 @@ export declare function createAdHocSecretHandler(): import("h3").EventHandlerWit
117
117
  } | {
118
118
  error: string;
119
119
  } | {
120
+ error?: undefined;
120
121
  ok: boolean;
121
122
  key: string;
122
- error?: undefined;
123
123
  } | {
124
+ error?: undefined;
124
125
  ok: boolean;
125
126
  removed: boolean;
126
- error?: undefined;
127
127
  }>>;
@@ -66,6 +66,7 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
66
66
  error: any;
67
67
  code: any;
68
68
  } | {
69
+ error?: undefined;
69
70
  errorCode?: undefined;
70
71
  code?: undefined;
71
72
  ok: boolean;
@@ -73,6 +74,5 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
73
74
  baseUrlKey?: string;
74
75
  scope: AgentEngineApiKeyScope;
75
76
  defaultModel?: import("./agent-engine-default-model-route.js").SavedKeyDefaultModelOutcome;
76
- error?: undefined;
77
77
  }>>;
78
78
  export {};
@@ -8,8 +8,8 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
8
8
  * resolveEngine's credential detection.
9
9
  */
10
10
  export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
11
- ok?: undefined;
12
11
  error: string;
12
+ ok?: undefined;
13
13
  scope?: undefined;
14
14
  } | {
15
15
  ok: boolean;
@@ -1,9 +1,9 @@
1
1
  export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
2
  error: string;
3
- models?: undefined;
4
3
  ok?: undefined;
4
+ models?: undefined;
5
5
  } | {
6
+ error?: undefined;
6
7
  ok: boolean;
7
8
  models: string[];
8
- error?: undefined;
9
9
  }>>;
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
54
54
  expiresAt?: undefined;
55
55
  ttlSeconds?: undefined;
56
56
  } | {
57
+ error?: undefined;
57
58
  token: string;
58
59
  expiresAt: string;
59
60
  ttlSeconds: number;
60
- error?: undefined;
61
61
  }>>;
@@ -20,6 +20,6 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- text: string;
24
23
  error?: undefined;
24
+ text: string;
25
25
  }>>;
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -3,8 +3,9 @@ name: review-prs
3
3
  description: >-
4
4
  Review recent BuilderIO/agent-native human pull requests, approve eligible
5
5
  internal PRs, and merge changes that are ready by Steve's bar. Use for
6
- scheduled or manual PR sweeps; flag external non-bug work and unresolved major
7
- product or UX decisions to Steve.
6
+ scheduled or manual PR sweeps; flag external work needing a major product
7
+ call or new framework API, and unresolved major product or UX decisions, to
8
+ Steve.
8
9
  user-invocable: true
9
10
  scope: dev
10
11
  metadata:
@@ -20,10 +21,12 @@ approve an external or unverified author.
20
21
 
21
22
  Approval and merge readiness are separate. A **Ready to merge by Steve's bar**
22
23
  result means merge the PR under the guarded merge procedure below. For a
23
- confirmed external author, only a clear bug fix enters evidence review and the
24
- possible merge flow; external authors are never eligible for an approval
25
- review. Surface other external work for Steve's explicit approval before a full
26
- review or merge; a scheduled or manual sweep is not that approval.
24
+ confirmed external author, a clear bug fix or a bounded improvement that
25
+ follows existing patterns enters evidence review and the possible merge flow;
26
+ external authors are never eligible for an approval review. Surface external
27
+ work that needs a major product call or a new framework API for Steve's explicit
28
+ approval before a full review or merge; a scheduled or manual sweep is not that
29
+ approval.
27
30
 
28
31
  ## Selection and evidence
29
32
 
@@ -53,6 +56,11 @@ author and draft state:
53
56
  summary to determine whether the PR already has a current, non-dismissed
54
57
  `APPROVED` review.
55
58
 
59
+ - Before the scope gate, check a confirmed nonmember's PR from a fork for
60
+ assignees. If any assignee is a verified current BuilderIO member, ignore
61
+ the PR completely, like a draft: that person owns it under `community-prs`.
62
+ Take no review, reply, or merge action, and leave it out of the recap.
63
+
56
64
  - Reuse that review as the code assessment only after verifying the reviewer
57
65
  is a different, current BuilderIO member and is eligible under the PR's
58
66
  author- and scope-specific rules, including any independent-review
@@ -99,17 +107,28 @@ the patch looks safe or the issue is obviously valid.
99
107
 
100
108
  ## External-contribution scope gate
101
109
 
110
+ Builder devs decide bounded outside contributions; Steve keeps major product
111
+ calls and new framework APIs.
112
+
102
113
  For an author the membership API confirms is not a current BuilderIO member,
103
- continue into the normal evidence sweep only for a clear bug fix: a change that
104
- corrects a specific reported or reproducible defect by restoring intended
105
- behavior. A feature, improvement, refactor, new or changed product behavior, or
106
- mixed bug-fix-and-enhancement scope is not a clear bug fix. If the title, issue,
107
- and initial diff do not establish a clear bug fix, treat it as non-bug work.
108
-
109
- For external non-bug work, stop before the full code review, approval or review
110
- action, merge-readiness disposition, author-facing draft, or merge. Report it to
111
- Steve as **Needs Steve's approval for scope**, with the PR link, author, stated
112
- scope, and why it is not a clear bug fix. Wait for Steve's explicit go-ahead on
114
+ continue into the normal evidence sweep for a clear bug fix or a bounded
115
+ improvement. A clear bug fix corrects a specific reported or reproducible
116
+ defect by restoring intended behavior. A bounded improvement stays within one
117
+ established workflow, app, or framework area and follows the patterns already
118
+ there.
119
+
120
+ External work needs Steve when it makes a major product call (as defined under
121
+ Product and UX decisions) or adds a new framework API: a new public export,
122
+ configuration option, action, plugin or hook contract, or CLI surface in a
123
+ published package under `packages/`. A fix or bounded improvement to an existing
124
+ API stays with devs when it keeps that API's contract. If the title, issue, and
125
+ initial diff do not establish a clear bug fix or a bounded improvement, treat it
126
+ as needing Steve.
127
+
128
+ For external work that needs Steve, stop before the full code review, approval
129
+ or review action, merge-readiness disposition, author-facing draft, or merge.
130
+ Report it to Steve as **Needs Steve's approval for scope**, with the PR link,
131
+ author, stated scope, and which call it needs. Wait for Steve's explicit go-ahead on
113
132
  that PR before continuing. Invoking or scheduling `review-prs`, approving a
114
133
  different PR, or prior approval of another external contribution does not
115
134
  authorize it. If membership is unknown, use the existing unknown-membership
@@ -118,6 +137,8 @@ solely because membership could not be verified. Keep the no-approval outcome,
118
137
  report the missing membership check, and assess merge readiness under the
119
138
  existing unknown-membership policy.
120
139
 
140
+ Builder devs own outside PRs end to end with `community-prs`.
141
+
121
142
  ## Liamdebeasi approval policy
122
143
 
123
144
  For a PR authored by the exact GitHub login `liamdebeasi` and immutable user
@@ -296,9 +317,10 @@ merge scope and must remain completely untouched.
296
317
  For a PR that fails an approval gate, do not submit an approval. Flag the exact
297
318
  concern and the evidence needed to resolve it. External or unverified authors
298
319
  never receive an approval review, but their PRs can still be merged when they
299
- meet the readiness gate below. Confirmed external bug fixes must also pass the
300
- external-contribution scope gate; confirmed external non-bug work remains
301
- stopped at Steve's approval gate. For unknown membership, do not apply the
320
+ meet the readiness gate below. Confirmed external PRs must also pass the
321
+ external-contribution scope gate; external work that needs a major product call
322
+ or a new framework API remains stopped at Steve's approval gate. For unknown
323
+ membership, do not apply the
302
324
  external scope gate solely because verification failed; preserve the
303
325
  no-approval outcome, assess readiness under the existing unknown-membership
304
326
  policy, and name the missing check.
@@ -504,7 +526,8 @@ non-auto-approved external PR that needs an update or screenshot, include its
504
526
  draft reply in a separate section, or mark it waiting on the contributor with
505
527
  a link to Steve's outstanding request. For internal PRs, report the needed
506
528
  update or screenshot without drafting an author-facing reply. Do not add rows
507
- for bots, `steve8708`, or drafts; those are ignored completely.
529
+ for bots, `steve8708`, drafts, or external PRs assigned to a BuilderIO member;
530
+ those are ignored completely.
508
531
 
509
532
  Use this shape:
510
533
 
@@ -525,4 +548,4 @@ blocker when the PR is ready and the guarded admin merge is available.
525
548
 
526
549
  ## Related skills
527
550
 
528
- `concurrent-agents`, `verifying-changes`, `ship`, `babysit-pr`
551
+ `concurrent-agents`, `verifying-changes`, `ship`, `babysit-pr`, `community-prs`
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -13,6 +13,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
13
13
  executionEngine?: string;
14
14
  executionCwd?: string;
15
15
  }, {
16
+ deleted?: undefined;
17
+ enabled?: undefined;
16
18
  created: boolean;
17
19
  name: string;
18
20
  scope: "organization" | "personal";
@@ -23,33 +25,31 @@ declare const _default: import("../../action.js").ActionDefinition<{
23
25
  reasoningEffort: "auto" | "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh";
24
26
  webhookPath: string;
25
27
  nextRun: string;
26
- deleted?: undefined;
27
- enabled?: undefined;
28
28
  executionHostId?: undefined;
29
29
  executionEngine?: undefined;
30
30
  executionCwd?: undefined;
31
31
  } | {
32
+ enabled?: undefined;
33
+ nextRun?: undefined;
32
34
  created?: undefined;
33
35
  scope?: undefined;
34
36
  triggerType?: undefined;
35
37
  event?: undefined;
36
38
  deleted: boolean;
37
39
  name: string;
38
- enabled?: undefined;
39
40
  schedule?: undefined;
40
41
  timezone?: undefined;
41
42
  reasoningEffort?: undefined;
42
43
  executionHostId?: undefined;
43
44
  executionEngine?: undefined;
44
45
  executionCwd?: undefined;
45
- nextRun?: undefined;
46
46
  webhookPath?: undefined;
47
47
  } | {
48
+ deleted?: undefined;
48
49
  created?: undefined;
49
50
  scope?: undefined;
50
51
  triggerType?: undefined;
51
52
  event?: undefined;
52
- deleted?: undefined;
53
53
  name: string;
54
54
  enabled: boolean;
55
55
  schedule: string;
@@ -324,7 +324,7 @@ What you throw decides how much of the message survives. `fail()` raises an `Act
324
324
  - **message**: the text the caller reads. Write it for a person, not for a log.
325
325
  - **options.errorCode**: a stable machine-readable code. Defaults to `"action_failed"`.
326
326
  - **options.statusCode**: the HTTP status for the action route. Defaults to `400`.
327
- - **options.details**: safe structured context for the caller. Never put secrets or raw driver output here.
327
+ - **options.details**: safe structured context for the caller, such as the id a retry needs. The browser and agents both receive it. Never put secrets or raw driver output here.
328
328
 
329
329
  The simplest call needs only a message:
330
330
 
@@ -402,7 +402,7 @@ A network drop, a proxy's HTML error page, and a bare status line author no mess
402
402
 
403
403
  So the status is not cosmetic. A refusal sent as `404` costs one round trip. The same refusal sent as a `500`, or thrown bare, costs four round trips and four duplicate error reports.
404
404
 
405
- Agent callers never see the status. The agent runs `run()` in process, so it receives the message directly whatever the type, as `Error running <action>: <message>`. An `errorCode` other than the default `action_failed` is appended as `(errorCode: not_found)` so the model can branch on it without parsing prose. External agents over MCP get the same text. Secrets in the message are redacted first, and the agent's own repeated-error breakers bound how many times it tries again.
405
+ Agent callers never see the status. The agent runs `run()` in process, so it receives the message directly whatever the type, as `Error running <action>: <message>`. An `errorCode` other than the default `action_failed` is appended as `(errorCode: not_found)` so the model can branch on it without parsing prose. `details` follow on their own line as compact JSON, such as `Error details: {"importId":"imp_1"}`, so an id the model needs for its next call doesn't have to be written into the message. External agents over MCP get the same text, and the same details in `structuredContent.error`. A tool that advertises an output schema (`mcpOutputSchema: true`) returns the text only, since a client may check an error result against that schema too. Details are capped at 2,000 characters: past that, small top-level entries are kept and the rest are listed as omitted. Secrets in the message and details are redacted first, and the agent's own repeated-error breakers bound how many times it tries again.
406
406
 
407
407
  ## Keep the action surface small {#small-surface}
408
408
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.210.0-nightly-20261019183757",
3
+ "version": "0.210.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -711,8 +711,8 @@
711
711
  "yaml": "^2.9.0",
712
712
  "yjs": "^13.6.33",
713
713
  "zod": "^4.3.6",
714
- "@agent-native/recap-cli": "^0.5.75-nightly-20261019183757",
715
- "@agent-native/agentkit": "^0.210.0-nightly-20261019183757"
714
+ "@agent-native/agentkit": "^0.210.0",
715
+ "@agent-native/recap-cli": "^0.5.75"
716
716
  },
717
717
  "devDependencies": {
718
718
  "@ai-sdk/anthropic": "^3.0.71",
@@ -782,7 +782,7 @@
782
782
  "xlsx": "^0.18.5"
783
783
  },
784
784
  "peerDependencies": {
785
- "@agent-native/core-corpus": "0.210.0-nightly-20261019183757",
785
+ "@agent-native/core-corpus": ">=0.196.0",
786
786
  "@ai-sdk/anthropic": ">=3",
787
787
  "@ai-sdk/cohere": ">=3",
788
788
  "@ai-sdk/google": ">=3",
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -3,8 +3,9 @@ name: review-prs
3
3
  description: >-
4
4
  Review recent BuilderIO/agent-native human pull requests, approve eligible
5
5
  internal PRs, and merge changes that are ready by Steve's bar. Use for
6
- scheduled or manual PR sweeps; flag external non-bug work and unresolved major
7
- product or UX decisions to Steve.
6
+ scheduled or manual PR sweeps; flag external work needing a major product
7
+ call or new framework API, and unresolved major product or UX decisions, to
8
+ Steve.
8
9
  user-invocable: true
9
10
  scope: dev
10
11
  metadata:
@@ -20,10 +21,12 @@ approve an external or unverified author.
20
21
 
21
22
  Approval and merge readiness are separate. A **Ready to merge by Steve's bar**
22
23
  result means merge the PR under the guarded merge procedure below. For a
23
- confirmed external author, only a clear bug fix enters evidence review and the
24
- possible merge flow; external authors are never eligible for an approval
25
- review. Surface other external work for Steve's explicit approval before a full
26
- review or merge; a scheduled or manual sweep is not that approval.
24
+ confirmed external author, a clear bug fix or a bounded improvement that
25
+ follows existing patterns enters evidence review and the possible merge flow;
26
+ external authors are never eligible for an approval review. Surface external
27
+ work that needs a major product call or a new framework API for Steve's explicit
28
+ approval before a full review or merge; a scheduled or manual sweep is not that
29
+ approval.
27
30
 
28
31
  ## Selection and evidence
29
32
 
@@ -53,6 +56,11 @@ author and draft state:
53
56
  summary to determine whether the PR already has a current, non-dismissed
54
57
  `APPROVED` review.
55
58
 
59
+ - Before the scope gate, check a confirmed nonmember's PR from a fork for
60
+ assignees. If any assignee is a verified current BuilderIO member, ignore
61
+ the PR completely, like a draft: that person owns it under `community-prs`.
62
+ Take no review, reply, or merge action, and leave it out of the recap.
63
+
56
64
  - Reuse that review as the code assessment only after verifying the reviewer
57
65
  is a different, current BuilderIO member and is eligible under the PR's
58
66
  author- and scope-specific rules, including any independent-review
@@ -99,17 +107,28 @@ the patch looks safe or the issue is obviously valid.
99
107
 
100
108
  ## External-contribution scope gate
101
109
 
110
+ Builder devs decide bounded outside contributions; Steve keeps major product
111
+ calls and new framework APIs.
112
+
102
113
  For an author the membership API confirms is not a current BuilderIO member,
103
- continue into the normal evidence sweep only for a clear bug fix: a change that
104
- corrects a specific reported or reproducible defect by restoring intended
105
- behavior. A feature, improvement, refactor, new or changed product behavior, or
106
- mixed bug-fix-and-enhancement scope is not a clear bug fix. If the title, issue,
107
- and initial diff do not establish a clear bug fix, treat it as non-bug work.
108
-
109
- For external non-bug work, stop before the full code review, approval or review
110
- action, merge-readiness disposition, author-facing draft, or merge. Report it to
111
- Steve as **Needs Steve's approval for scope**, with the PR link, author, stated
112
- scope, and why it is not a clear bug fix. Wait for Steve's explicit go-ahead on
114
+ continue into the normal evidence sweep for a clear bug fix or a bounded
115
+ improvement. A clear bug fix corrects a specific reported or reproducible
116
+ defect by restoring intended behavior. A bounded improvement stays within one
117
+ established workflow, app, or framework area and follows the patterns already
118
+ there.
119
+
120
+ External work needs Steve when it makes a major product call (as defined under
121
+ Product and UX decisions) or adds a new framework API: a new public export,
122
+ configuration option, action, plugin or hook contract, or CLI surface in a
123
+ published package under `packages/`. A fix or bounded improvement to an existing
124
+ API stays with devs when it keeps that API's contract. If the title, issue, and
125
+ initial diff do not establish a clear bug fix or a bounded improvement, treat it
126
+ as needing Steve.
127
+
128
+ For external work that needs Steve, stop before the full code review, approval
129
+ or review action, merge-readiness disposition, author-facing draft, or merge.
130
+ Report it to Steve as **Needs Steve's approval for scope**, with the PR link,
131
+ author, stated scope, and which call it needs. Wait for Steve's explicit go-ahead on
113
132
  that PR before continuing. Invoking or scheduling `review-prs`, approving a
114
133
  different PR, or prior approval of another external contribution does not
115
134
  authorize it. If membership is unknown, use the existing unknown-membership
@@ -118,6 +137,8 @@ solely because membership could not be verified. Keep the no-approval outcome,
118
137
  report the missing membership check, and assess merge readiness under the
119
138
  existing unknown-membership policy.
120
139
 
140
+ Builder devs own outside PRs end to end with `community-prs`.
141
+
121
142
  ## Liamdebeasi approval policy
122
143
 
123
144
  For a PR authored by the exact GitHub login `liamdebeasi` and immutable user
@@ -296,9 +317,10 @@ merge scope and must remain completely untouched.
296
317
  For a PR that fails an approval gate, do not submit an approval. Flag the exact
297
318
  concern and the evidence needed to resolve it. External or unverified authors
298
319
  never receive an approval review, but their PRs can still be merged when they
299
- meet the readiness gate below. Confirmed external bug fixes must also pass the
300
- external-contribution scope gate; confirmed external non-bug work remains
301
- stopped at Steve's approval gate. For unknown membership, do not apply the
320
+ meet the readiness gate below. Confirmed external PRs must also pass the
321
+ external-contribution scope gate; external work that needs a major product call
322
+ or a new framework API remains stopped at Steve's approval gate. For unknown
323
+ membership, do not apply the
302
324
  external scope gate solely because verification failed; preserve the
303
325
  no-approval outcome, assess readiness under the existing unknown-membership
304
326
  policy, and name the missing check.
@@ -504,7 +526,8 @@ non-auto-approved external PR that needs an update or screenshot, include its
504
526
  draft reply in a separate section, or mark it waiting on the contributor with
505
527
  a link to Steve's outstanding request. For internal PRs, report the needed
506
528
  update or screenshot without drafting an author-facing reply. Do not add rows
507
- for bots, `steve8708`, or drafts; those are ignored completely.
529
+ for bots, `steve8708`, drafts, or external PRs assigned to a BuilderIO member;
530
+ those are ignored completely.
508
531
 
509
532
  Use this shape:
510
533
 
@@ -525,4 +548,4 @@ blocker when the PR is ready and the guarded admin merge is available.
525
548
 
526
549
  ## Related skills
527
550
 
528
- `concurrent-agents`, `verifying-changes`, `ship`, `babysit-pr`
551
+ `concurrent-agents`, `verifying-changes`, `ship`, `babysit-pr`, `community-prs`
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179
 
@@ -170,10 +170,10 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
170
170
  - **Do** keep one action, one job; document a reusable action (when to use it, key args, return fields to preserve) in `AGENTS.md` once it's called from outside one narrow screen; promote workflow-heavy actions (provider-backed, cross-app, MCP/A2A, multi-step) into a skill.
171
171
  - **Do** use `fail(message, { errorCode, statusCode })` for user-friendly errors and import primitives from `@agent-native/core`(`/action`) instead of redefining them; use the core `upload-image` action or `uploadFile()` for durable images/files — never base64 into SQL, markdown, or action results.
172
172
  - **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
173
- - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser; unexpected errors become a generic 500. Reserve bare throws for internal faults.
173
+ - **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
174
174
  - **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
175
175
  - **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
176
- - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP; `details` and the status never reach either.
176
+ - **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
177
177
  - **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
178
178
  - **Don't** reach for provider integrations, `outputSchema`, `authorize`, `needsApproval`, or `_agentImages` without checking `references/` first — each has sharp edges covered there, not here.
179
179