@nathapp/nax-agent 0.91.7 → 0.91.8-canary.2

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 (87) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/config/catalog-overrides.d.ts +13 -0
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +1 -0
  5. package/dist/internal/atomic-write.d.ts +22 -7
  6. package/dist/internal/atomic-write.js +107 -12
  7. package/dist/internal/pinned-directory-worker.d.ts +52 -0
  8. package/dist/internal/pinned-directory-worker.js +105 -0
  9. package/dist/internal/pinned-directory.d.ts +48 -0
  10. package/dist/internal/pinned-directory.js +168 -0
  11. package/dist/internal.d.ts +2 -0
  12. package/dist/internal.js +2 -0
  13. package/dist/memory/delivery.d.ts +38 -0
  14. package/dist/memory/delivery.js +28 -0
  15. package/dist/memory/index-render.d.ts +55 -0
  16. package/dist/memory/index-render.js +225 -0
  17. package/dist/memory/index.d.ts +12 -0
  18. package/dist/memory/index.js +11 -0
  19. package/dist/memory/local-provider.d.ts +3 -0
  20. package/dist/memory/local-provider.js +127 -0
  21. package/dist/memory/mirror-lock.d.ts +109 -0
  22. package/dist/memory/mirror-lock.js +334 -0
  23. package/dist/memory/note.d.ts +15 -0
  24. package/dist/memory/note.js +131 -0
  25. package/dist/memory/operations.d.ts +123 -0
  26. package/dist/memory/operations.js +471 -0
  27. package/dist/memory/outbox.d.ts +35 -0
  28. package/dist/memory/outbox.js +289 -0
  29. package/dist/memory/provider-types.d.ts +50 -0
  30. package/dist/memory/provider-types.js +1 -0
  31. package/dist/memory/records.d.ts +41 -0
  32. package/dist/memory/records.js +93 -0
  33. package/dist/memory/refusal.d.ts +36 -0
  34. package/dist/memory/refusal.js +25 -0
  35. package/dist/memory/search.d.ts +17 -0
  36. package/dist/memory/search.js +112 -0
  37. package/dist/memory/store.d.ts +106 -0
  38. package/dist/memory/store.js +459 -0
  39. package/dist/memory/support.d.ts +63 -0
  40. package/dist/memory/support.js +98 -0
  41. package/dist/memory/sync-flight.d.ts +25 -0
  42. package/dist/memory/sync-flight.js +65 -0
  43. package/dist/memory/sync.d.ts +82 -0
  44. package/dist/memory/sync.js +344 -0
  45. package/dist/memory/types.d.ts +108 -0
  46. package/dist/memory/types.js +51 -0
  47. package/dist/memory/validate.d.ts +31 -0
  48. package/dist/memory/validate.js +104 -0
  49. package/dist/native/adapter-deps.d.ts +9 -0
  50. package/dist/native/adapter-deps.js +9 -0
  51. package/dist/native/models.js +3 -0
  52. package/dist/native/session/compaction.d.ts +15 -1
  53. package/dist/native/session/compaction.js +90 -23
  54. package/dist/native/session/manual-compaction.d.ts +57 -0
  55. package/dist/native/session/manual-compaction.js +72 -0
  56. package/dist/native/session/session-summarizer.d.ts +75 -0
  57. package/dist/native/session/session-summarizer.js +73 -0
  58. package/dist/native/session/transcript-identity.d.ts +12 -0
  59. package/dist/native/session/transcript-identity.js +16 -0
  60. package/dist/native/session/turn-compaction-step.d.ts +30 -2
  61. package/dist/native/session/turn-compaction-step.js +7 -1
  62. package/dist/native/session/turn-loop-round-trip.js +71 -17
  63. package/dist/native/session/turn-loop.js +2 -6
  64. package/dist/native/session-adapter.d.ts +19 -0
  65. package/dist/native/session-adapter.js +42 -64
  66. package/dist/sandbox/srt-backend.js +9 -16
  67. package/dist/session/agent-session-options.js +1 -0
  68. package/dist/session/agent-session-turn.d.ts +6 -0
  69. package/dist/session/agent-session-turn.js +5 -4
  70. package/dist/session/agent-session-types.d.ts +38 -0
  71. package/dist/session/agent-session.d.ts +8 -0
  72. package/dist/session/agent-session.js +163 -20
  73. package/dist/session/native-backend.js +8 -0
  74. package/dist/session/session-backend.d.ts +19 -1
  75. package/dist/session/session-types.d.ts +6 -0
  76. package/dist/session/steer-channel.d.ts +36 -0
  77. package/dist/session/steer-channel.js +39 -0
  78. package/dist/session-store/index.d.ts +1 -1
  79. package/dist/session-store/index.js +1 -1
  80. package/dist/session-store/session-lock.d.ts +2 -2
  81. package/dist/session-store/session-lock.js +4 -2
  82. package/dist/tools/ask-request.d.ts +8 -0
  83. package/dist/tools/ask-request.js +34 -1
  84. package/dist/tools/provider-adapt.js +5 -1
  85. package/dist/tools/provider-types.d.ts +7 -0
  86. package/dist/tools/types.d.ts +16 -0
  87. package/package.json +4 -4
@@ -17,6 +17,14 @@ export const MAX_ASK_SUMMARY_CHARS = 200;
17
17
  * a Write, a commit message, whatever a provider tool takes -- and an
18
18
  * AskResolver is by definition an outbound channel to a human. A summary is
19
19
  * what approval needs; the payload is what the audit sink already holds.
20
+ *
21
+ * Two kinds of declared field, and only these: the parts that say WHAT the
22
+ * call will do (command, argv, verb, paths), and the summary-only fields a tool
23
+ * adds for legibility (`ToolScope.summaryFields`) -- a memory tool's `slug`,
24
+ * so the person reads which note is about to be written instead of the same
25
+ * line the tool always rendered. Neither kind is grant-checked here, and
26
+ * neither is ever widened into the payload: a summary field renders only a
27
+ * string, number or boolean.
20
28
  */
21
29
  export function askSummary(tool, scope, input) {
22
30
  const fields = [scope.commandField, scope.argvField, scope.verbField, ...scope.pathFields];
@@ -30,13 +38,38 @@ export function askSummary(tool, scope, input) {
30
38
  return [`${field}=${value.filter((v) => typeof v === "string").join(" ")}`];
31
39
  return [];
32
40
  });
41
+ // Summary fields FOLLOW the parts above, so a path-bearing tool keeps its
42
+ // existing line and gains the extra detail at the end.
43
+ const summaryParts = (scope.summaryFields ?? []).flatMap((field) => {
44
+ const rendered = summaryScalar(input[field]);
45
+ return rendered === undefined ? [] : [`${field}=${rendered}`];
46
+ });
33
47
  // Mask the FULL line, then cut: cutting first can split a secret so no
34
48
  // pattern matches what is left, and the partial secret would go out.
35
- const masked = maskForPrompt(`${tool} ${parts.join(" ")}`.trim());
49
+ const masked = maskForPrompt(`${tool} ${[...parts, ...summaryParts].join(" ")}`.trim());
36
50
  if (!masked.ok)
37
51
  return { summary: `${tool} [arguments withheld: contains a secret]`, unshowable: true };
38
52
  return { summary: masked.masked.slice(0, MAX_ASK_SUMMARY_CHARS), unshowable: false };
39
53
  }
54
+ /** One line break, whichever convention wrote it: CRLF before CR and LF alone. */
55
+ const SUMMARY_LINE_BREAK = /\r\n|\r|\n/g;
56
+ /**
57
+ * The one-line form of a summary field's value, or undefined when the value is
58
+ * not renderable.
59
+ *
60
+ * Scalars only. An array or an object is SKIPPED rather than serialised: a
61
+ * summary line describes the call, and a serialised payload on it would be the
62
+ * very thing this function exists to avoid. A line break inside a value
63
+ * becomes one space, because the line is a single line -- an unstripped newline
64
+ * would let a field forge a second line of the approval card.
65
+ */
66
+ function summaryScalar(value) {
67
+ if (typeof value === "string")
68
+ return value.replace(SUMMARY_LINE_BREAK, " ");
69
+ if (typeof value === "number" || typeof value === "boolean")
70
+ return String(value);
71
+ return undefined;
72
+ }
40
73
  /** The clause `unsandboxedReasonSuffix` renders, before the reason itself. */
41
74
  const UNSANDBOXED_PREFIX = " -- runs OUTSIDE the sandbox: ";
42
75
  /** What the suffix says when the model gave no usable reason. */
@@ -26,7 +26,11 @@ export function adaptProviderTool(providerId, tool) {
26
26
  inputSchema: tool.inputSchema,
27
27
  // No path fields and no verb field: the grant lookup is the whole gate,
28
28
  // which is the honest expression for a tool whose arguments are not paths.
29
- scope: { pathFields: [] },
29
+ // A declared summary field is carried through, summary-only — it names the
30
+ // call on an approval line and is never checked. Absent, the scope stays
31
+ // exactly `{ pathFields: [] }`, so a metadata-free provider tool adapts to
32
+ // the same shape it always did.
33
+ scope: tool.summaryFields === undefined ? { pathFields: [] } : { pathFields: [], summaryFields: tool.summaryFields },
30
34
  run: (input, ctx) => tool.run(input, ctx),
31
35
  };
32
36
  }
@@ -24,6 +24,13 @@ export interface ProviderTool {
24
24
  * trusted as stated and decides whether an ask-profile session asks first.
25
25
  */
26
26
  readonly readOnly?: boolean;
27
+ /**
28
+ * US-003: plain input fields an approval line may SHOW, copied verbatim into
29
+ * the adapted tool's `scope.summaryFields`. Summary-only — never grant-checked
30
+ * and never rendered as a path (see `ToolScope.summaryFields`). Absent for
31
+ * every memory tool's note BODY, which is never shown on an approval line.
32
+ */
33
+ readonly summaryFields?: readonly string[];
27
34
  run(input: Record<string, unknown>, ctx: ToolRunContext): Promise<ToolResult>;
28
35
  }
29
36
  export interface ToolProvider {
@@ -118,6 +118,22 @@ export interface ToolScope {
118
118
  * option, and whether a call is PERMITTED is the runtime's decision.
119
119
  */
120
120
  readonly unsandboxedField?: string;
121
+ /**
122
+ * Plain input fields an approval line may SHOW, in declaration order
123
+ * (`askSummary`). Summary-only in the strictest sense: they are never
124
+ * grant-checked, never resolved as paths, never treated as a verb or a
125
+ * command, and never widen what an approval admits. They exist because a
126
+ * tool whose arguments are not paths — an MCP memory tool, say — otherwise
127
+ * renders an approval line naming nothing about the call.
128
+ *
129
+ * Only a string, number or boolean value is rendered (line breaks flattened
130
+ * to a space); an array or an object is skipped rather than serialised, since
131
+ * a summary is a one-line description and not a payload dump. Being
132
+ * summary-only, this field is deliberately absent from `isFieldlessScope`
133
+ * (policy.ts): a tool declaring summary fields is still fieldless, so an
134
+ * unconditional ask rule keeps asking exactly as it did before.
135
+ */
136
+ readonly summaryFields?: readonly string[];
121
137
  }
122
138
  /**
123
139
  * `breach` separates "you may not write there" from "that path is not in this
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax-agent",
3
- "version": "0.91.7",
3
+ "version": "0.91.8-canary.2",
4
4
  "description": "nax's native coding agent: session contract, native loop, tools, permissions, sandbox, command-safety.",
5
5
  "license": "MIT",
6
6
  "author": "William Khoo",
@@ -47,13 +47,13 @@
47
47
  "dependencies": {
48
48
  "@anthropic-ai/sandbox-runtime": "0.0.77",
49
49
  "@modelcontextprotocol/sdk": "^1.32.1",
50
- "@nathapp/nax-ai": "0.91.7",
51
- "zod": "^4.3.6"
50
+ "@nathapp/nax-ai": "0.91.8-canary.2",
51
+ "zod": "^4.6.6"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public",
55
55
  "registry": "https://registry.npmjs.org/",
56
56
  "provenance": true,
57
- "tag": "latest"
57
+ "tag": "canary"
58
58
  }
59
59
  }