@agent-native/core 0.203.0 → 0.203.1-nightly-20261007154213

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 (50) hide show
  1. package/dist/action.d.ts +34 -0
  2. package/dist/agent/clip-text.d.ts +4 -0
  3. package/dist/agent/clip-text.js +17 -0
  4. package/dist/agent/follow-up-suggestions.d.ts +16 -2
  5. package/dist/agent/follow-up-suggestions.js +69 -1
  6. package/dist/agent/production-agent.d.ts +20 -2
  7. package/dist/agent/production-agent.js +322 -132
  8. package/dist/agent/provider-model-selection.d.ts +21 -2
  9. package/dist/agent/provider-model-selection.js +19 -2
  10. package/dist/agent/run-loop-with-resume.js +2 -16
  11. package/dist/agent/tool-search.d.ts +31 -1
  12. package/dist/agent/tool-search.js +196 -15
  13. package/dist/agent/write-receipts.d.ts +27 -0
  14. package/dist/agent/write-receipts.js +181 -0
  15. package/dist/automation/index.d.ts +1 -1
  16. package/dist/collab/routes.d.ts +2 -2
  17. package/dist/collab/struct-routes.d.ts +1 -1
  18. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  19. package/dist/observability/routes.d.ts +10 -10
  20. package/dist/observability/trace-error.d.ts +5 -3
  21. package/dist/observability/trace-error.js +29 -4
  22. package/dist/observability/traces.js +6 -0
  23. package/dist/org/handlers.d.ts +2 -2
  24. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  25. package/dist/resources/handlers.d.ts +1 -1
  26. package/dist/secrets/routes.d.ts +5 -5
  27. package/dist/server/action-routes.js +3 -0
  28. package/dist/server/agent-chat/prompt-resources.d.ts +13 -0
  29. package/dist/server/agent-chat/prompt-resources.js +21 -12
  30. package/dist/server/agent-chat-plugin.js +25 -9
  31. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  32. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  33. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  34. package/dist/server/embed-route.js +2 -1
  35. package/dist/server/index.d.ts +3 -3
  36. package/dist/server/index.js +3 -3
  37. package/dist/server/realtime-voice.js +2 -4
  38. package/dist/shared/embed-auth.d.ts +1 -0
  39. package/dist/shared/embed-auth.js +1 -0
  40. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  41. package/dist/templates/chat/.agents/skills/actions/SKILL.md +25 -0
  42. package/dist/templates/default/.agents/skills/actions/SKILL.md +25 -0
  43. package/dist/templates/headless/.agents/skills/actions/SKILL.md +25 -0
  44. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +25 -0
  45. package/dist/triggers/actions/manage-automation.d.ts +7 -7
  46. package/package.json +3 -3
  47. package/src/templates/chat/.agents/skills/actions/SKILL.md +25 -0
  48. package/src/templates/default/.agents/skills/actions/SKILL.md +25 -0
  49. package/src/templates/headless/.agents/skills/actions/SKILL.md +25 -0
  50. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +25 -0
package/dist/action.d.ts CHANGED
@@ -36,6 +36,8 @@ export interface ActionRunContext {
36
36
  attachments?: AgentChatAttachment[];
37
37
  signal?: AbortSignal;
38
38
  actionName?: string;
39
+ /** Present only on frontend GETs authorized by a scoped directory-widget read capability. */
40
+ mcpDirectoryWidgetReadOnly?: true;
39
41
  threadId?: string;
40
42
  runId?: string;
41
43
  turnId?: string;
@@ -67,6 +69,38 @@ export interface FailOptions {
67
69
  details?: Record<string, unknown>;
68
70
  }
69
71
  export declare function fail(message: string, options?: FailOptions): never;
72
+ /**
73
+ * What a write action verified about its own effect. An action opts in by
74
+ * returning a plain-object result with a reserved `_receipt: WriteReceipt`.
75
+ * The agent loop reads it before the result is stringified and truncated, so
76
+ * the final answer is reconciled with what the write did instead of with the
77
+ * model's reading of a JSON string.
78
+ *
79
+ * - `changed: false`: nothing was written (a no-op); not a completed side effect.
80
+ * - `verified: true`: the effect was observed. `false`: it was checked and did
81
+ * not hold. `"unverified"`: it could not be checked.
82
+ * - `subject`: the stable target of the write, such as a dashboard id. Later
83
+ * receipts from the same action with the same subject that are `changed` and
84
+ * `verified: true` supersede this one, so a no-op that was then fixed does
85
+ * not flag the answer. A receipt with failing checks is superseded only when
86
+ * those later receipts carry an `ok` check with the same `id` for every
87
+ * check that failed here, because a verified write speaks only for what it
88
+ * checked. Without a subject a receipt is never superseded.
89
+ * - Bounds, enforced by the loop: summary and subject 200 chars, 8 checks, 5
90
+ * warnings.
91
+ */
92
+ export interface WriteReceipt {
93
+ changed: boolean;
94
+ verified: true | false | "unverified";
95
+ summary: string;
96
+ subject?: string;
97
+ checks?: Array<{
98
+ id: string;
99
+ ok: boolean;
100
+ detail?: string;
101
+ }>;
102
+ warnings?: string[];
103
+ }
70
104
  export declare class AgentActionStopError extends Error {
71
105
  readonly agentNativeStop = true;
72
106
  readonly errorCode?: string;
@@ -0,0 +1,4 @@
1
+ /** At most the first `max` UTF-16 units of `text`, never ending inside a surrogate pair. */
2
+ export declare function clipHead(text: string, max: number): string;
3
+ /** At most the last `max` UTF-16 units of `text`, never starting inside a surrogate pair. */
4
+ export declare function clipTail(text: string, max: number): string;
@@ -0,0 +1,17 @@
1
+ // Provider APIs reject a request whose JSON holds half a surrogate pair, so a
2
+ // clip that lands inside an emoji must drop the half instead of keeping it.
3
+ const isHighSurrogate = (unit) => unit >= 0xd800 && unit <= 0xdbff;
4
+ const isLowSurrogate = (unit) => unit >= 0xdc00 && unit <= 0xdfff;
5
+ /** At most the first `max` UTF-16 units of `text`, never ending inside a surrogate pair. */
6
+ export function clipHead(text, max) {
7
+ if (text.length <= max)
8
+ return text;
9
+ return text.slice(0, isHighSurrogate(text.charCodeAt(max - 1)) ? max - 1 : max);
10
+ }
11
+ /** At most the last `max` UTF-16 units of `text`, never starting inside a surrogate pair. */
12
+ export function clipTail(text, max) {
13
+ if (text.length <= max)
14
+ return text;
15
+ const start = text.length - max;
16
+ return text.slice(isLowSurrogate(text.charCodeAt(start)) ? start + 1 : start);
17
+ }
@@ -1,11 +1,25 @@
1
1
  import type { AgentSuggestion } from "@agent-native/agentkit/protocol";
2
2
  import { z } from "zod";
3
- import type { EngineTool } from "./engine/types.js";
3
+ import type { EngineMessage, EngineTool } from "./engine/types.js";
4
4
  export declare const FOLLOW_UP_SUGGESTIONS_TOOL_NAME = "suggest-follow-ups";
5
5
  export declare const FOLLOW_UP_SUGGESTIONS_MAX_OUTPUT_TOKENS = 1024;
6
6
  export declare const FOLLOW_UP_SUGGESTIONS_INSTRUCTION: string;
7
+ export declare const FOLLOW_UP_SUGGESTIONS_COMPLETION_SYSTEM_PROMPT = "You write follow-up suggestions for a conversation between a user and an AI agent inside an app. You only record them by calling suggest-follow-ups.";
7
8
  export declare const FOLLOW_UP_SUGGESTIONS_COMPLETION_INSTRUCTION: string;
8
- export type FollowUpSuggestionsFailure = "budget_exhausted" | "iteration_limit" | "interrupted" | "context_error" | "processor_error" | "provider_error" | "invalid_or_missing";
9
+ /**
10
+ * The completion call sends a different tools array than the turn did, so it
11
+ * can never read the turn's prompt cache. It carries a bounded digest of the
12
+ * turn instead of re-prefilling the whole conversation at full price. The
13
+ * digest keeps the shape of a finished turn (request, reply, then the
14
+ * instruction as the last user message) so role alternation is valid for every
15
+ * provider and the instruction stays the message a prefix match finds.
16
+ */
17
+ export declare function buildFollowUpCompletionMessages(input: {
18
+ requestText?: string;
19
+ replyText: string;
20
+ toolNames: readonly string[];
21
+ }): EngineMessage[];
22
+ export type FollowUpSuggestionsFailure = "budget_exhausted" | "iteration_limit" | "interrupted" | "processor_error" | "provider_error" | "invalid_or_missing";
9
23
  declare const followUpSuggestionsSchema: z.ZodObject<{
10
24
  suggestions: z.ZodArray<z.ZodObject<{
11
25
  label: z.ZodString;
@@ -1,10 +1,78 @@
1
1
  import { z } from "zod";
2
+ import { clipHead, clipTail } from "./clip-text.js";
2
3
  export const FOLLOW_UP_SUGGESTIONS_TOOL_NAME = "suggest-follow-ups";
3
4
  export const FOLLOW_UP_SUGGESTIONS_MAX_OUTPUT_TOKENS = 1024;
4
5
  export const FOLLOW_UP_SUGGESTIONS_INSTRUCTION = "Before finishing this turn, evaluate useful next actions grounded in the user's request, conversation, app workflow/current context, and observed results. " +
5
6
  "Record your decision with suggest-follow-ups: zero to three meaningful next intents, or an empty list when none is warranted. Do not fill a quota or repeat completed work.";
6
- export const FOLLOW_UP_SUGGESTIONS_COMPLETION_INSTRUCTION = "The final reply above has already been delivered. Complete only its missing follow-up metadata by calling suggest-follow-ups once, using the conversation, current app context, and completed results. " +
7
+ export const FOLLOW_UP_SUGGESTIONS_COMPLETION_SYSTEM_PROMPT = "You write follow-up suggestions for a conversation between a user and an AI agent inside an app. You only record them by calling suggest-follow-ups.";
8
+ export const FOLLOW_UP_SUGGESTIONS_COMPLETION_INSTRUCTION = "The final reply above has already been delivered. Complete only its missing follow-up metadata by calling suggest-follow-ups once, using the request, reply, and tools used above. " +
7
9
  "An empty list is valid when no useful next action exists. Do not repeat the reply, perform more work, or call other tools.";
10
+ // The ask sits at the end of a long pasted document and a long reply's
11
+ // conclusions sit at the end, so a clip keeps the tail.
12
+ const COMPLETION_REQUEST_HEAD_CHARS = 500;
13
+ const COMPLETION_REQUEST_TAIL_CHARS = 1_500;
14
+ const COMPLETION_REPLY_TAIL_CHARS = 4_000;
15
+ const MAX_COMPLETION_TOOL_NAMES = 30;
16
+ function clipMiddle(text, head, tail) {
17
+ return text.length > head + tail
18
+ ? `${clipHead(text, head)}\n…\n${clipTail(text, tail)}`
19
+ : text;
20
+ }
21
+ // Providers reject an empty first user message or an empty assistant text, so a
22
+ // turn with no request text or no reply text still sends a stated absence.
23
+ const NO_REQUEST_TEXT = "(No request text was recorded for this turn.)";
24
+ const NO_REPLY_TEXT = "(The reply had no text.)";
25
+ /**
26
+ * The completion call sends a different tools array than the turn did, so it
27
+ * can never read the turn's prompt cache. It carries a bounded digest of the
28
+ * turn instead of re-prefilling the whole conversation at full price. The
29
+ * digest keeps the shape of a finished turn (request, reply, then the
30
+ * instruction as the last user message) so role alternation is valid for every
31
+ * provider and the instruction stays the message a prefix match finds.
32
+ */
33
+ export function buildFollowUpCompletionMessages(input) {
34
+ const requestText = input.requestText?.trim();
35
+ const replyText = input.replyText.trim();
36
+ const toolNames = [...new Set(input.toolNames)]
37
+ .filter((name) => name !== FOLLOW_UP_SUGGESTIONS_TOOL_NAME)
38
+ .slice(0, MAX_COMPLETION_TOOL_NAMES);
39
+ const request = [
40
+ requestText
41
+ ? `<user-request>\n${clipMiddle(requestText, COMPLETION_REQUEST_HEAD_CHARS, COMPLETION_REQUEST_TAIL_CHARS)}\n</user-request>`
42
+ : "",
43
+ toolNames.length > 0
44
+ ? `<tools-used>${toolNames.join(", ")}</tools-used>`
45
+ : "",
46
+ ].filter(Boolean);
47
+ return [
48
+ {
49
+ role: "user",
50
+ content: [
51
+ {
52
+ type: "text",
53
+ text: request.length > 0 ? request.join("\n\n") : NO_REQUEST_TEXT,
54
+ },
55
+ ],
56
+ },
57
+ {
58
+ role: "assistant",
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: replyText
63
+ ? clipMiddle(replyText, 0, COMPLETION_REPLY_TAIL_CHARS)
64
+ : NO_REPLY_TEXT,
65
+ },
66
+ ],
67
+ },
68
+ {
69
+ role: "user",
70
+ content: [
71
+ { type: "text", text: FOLLOW_UP_SUGGESTIONS_COMPLETION_INSTRUCTION },
72
+ ],
73
+ },
74
+ ];
75
+ }
8
76
  const followUpSuggestionsSchema = z
9
77
  .strictObject({
10
78
  suggestions: z
@@ -1,7 +1,7 @@
1
1
  import type { EventHandler as H3EventHandler } from "h3";
2
2
  import "../authorization/check-action.js";
3
3
  import type { Task } from "../a2a/types.js";
4
- import { type ActionAutomationContext, type ActionCaller } from "../action.js";
4
+ import { type ActionAutomationContext, type ActionCaller, type WriteReceipt } from "../action.js";
5
5
  import { type ArtifactReceipt } from "../artifacts/detect.js";
6
6
  import type { AgentNativeHarnessSetting } from "../config.js";
7
7
  import { type CredentialProvenance } from "../credentials/index.js";
@@ -19,6 +19,7 @@ import { subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getR
19
19
  import type { ActiveRun } from "./run-manager.js";
20
20
  import { type AgentTurnInitiator, insertRun, isTurnAborted, markRunAborted, updateRunHeartbeat, updateRunStatusIfRunning, setRunError, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, countRunsForTurn } from "./run-store.js";
21
21
  import { type AgentActionScope, ActionTool, AgentChatAttachment, AgentChatEvent, AgentFileMutationProof, AgentChatReference, AgentChatStructuredMessage } from "./types.js";
22
+ import { type ToolWriteReceipt } from "./write-receipts.js";
22
23
  export { PROVIDER_TO_ENV };
23
24
  /**
24
25
  * Grace window + poll interval for the foreground circuit-breaker that confirms
@@ -394,6 +395,12 @@ export interface AgentLoopUsage {
394
395
  engineName?: string;
395
396
  model: string;
396
397
  llmCalls?: number;
398
+ /** Wall time and input tokens of the end-of-turn follow-up suggestions call. */
399
+ followUpMs?: number;
400
+ followUpInputTokens?: number;
401
+ /** Write receipts this run with `verified` other than true / with `changed: false`. */
402
+ receiptUnverifiedCount?: number;
403
+ receiptChangedFalseCount?: number;
397
404
  /**
398
405
  * True once the engine reported at least one real `usage` event for this
399
406
  * run. The token fields above start at 0 and are only ever incremented —
@@ -404,6 +411,12 @@ export interface AgentLoopUsage {
404
411
  usageReported?: boolean;
405
412
  firstEngineEventAtMs?: number;
406
413
  }
414
+ /**
415
+ * Folds one loop attempt's usage into a running total. Every wrapper that
416
+ * re-enters `runAgentLoop` merges through this, so a field added to
417
+ * `AgentLoopUsage` cannot be reported by the loop and dropped by a wrapper.
418
+ */
419
+ export declare function mergeAgentLoopUsage(total: AgentLoopUsage, next: AgentLoopUsage): void;
407
420
  export type AgentLoopOutcome = {
408
421
  state: "completed";
409
422
  } | {
@@ -428,7 +441,10 @@ export interface AgentLoopToolResultSummary {
428
441
  content: string;
429
442
  isError: boolean;
430
443
  artifacts?: ArtifactReceipt[];
444
+ /** The action's `_receipt`, read before the result was truncated. */
445
+ receipt?: WriteReceipt;
431
446
  }
447
+ export type { ToolWriteReceipt };
432
448
  export interface AgentLoopFinalResponseGuardContext {
433
449
  messages: EngineMessage[];
434
450
  requestText?: string;
@@ -436,6 +452,8 @@ export interface AgentLoopFinalResponseGuardContext {
436
452
  text: string;
437
453
  toolCalls: AgentLoopToolCallSummary[];
438
454
  toolResults: AgentLoopToolResultSummary[];
455
+ /** Every write receipt this turn; set by the loop, absent only in hand-built contexts. */
456
+ receipts?: ToolWriteReceipt[];
439
457
  retryCount: number;
440
458
  executionMode: AgentExecutionMode;
441
459
  }
@@ -792,7 +810,7 @@ export declare function resolveAgentRequestReasoningEffort({ model, requestEffor
792
810
  requestEffort?: unknown;
793
811
  configuredEffort?: ReasoningEffort;
794
812
  }): ReasoningEffort | undefined;
795
- export type AgentModelSelectionSource = "request" | "configured" | "stored" | "default";
813
+ export type AgentModelSelectionSource = "request" | "configured" | "stored" | "default" | "provider-selection-fallback";
796
814
  export declare function resolveAgentModelSelection(options: {
797
815
  requestModel?: string | null;
798
816
  configuredModel?: string | null;