primitive-admin 1.2.0-alpha.1 → 1.2.0-alpha.3

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 (129) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/primitive.js +22 -24
  3. package/dist/bin/primitive.js.map +1 -1
  4. package/dist/src/commands/agent-sessions.d.ts +20 -0
  5. package/dist/src/commands/agent-sessions.js +275 -0
  6. package/dist/src/commands/agent-sessions.js.map +1 -0
  7. package/dist/src/commands/apps-children.d.ts +54 -0
  8. package/dist/src/commands/apps-children.js +578 -0
  9. package/dist/src/commands/apps-children.js.map +1 -0
  10. package/dist/src/commands/apps.js +88 -9
  11. package/dist/src/commands/apps.js.map +1 -1
  12. package/dist/src/commands/auth-sessions.d.ts +3 -3
  13. package/dist/src/commands/auth-sessions.js +117 -23
  14. package/dist/src/commands/auth-sessions.js.map +1 -1
  15. package/dist/src/commands/auth.js +248 -15
  16. package/dist/src/commands/auth.js.map +1 -1
  17. package/dist/src/commands/documents.d.ts +29 -0
  18. package/dist/src/commands/documents.js +676 -191
  19. package/dist/src/commands/documents.js.map +1 -1
  20. package/dist/src/commands/env.d.ts +9 -1
  21. package/dist/src/commands/env.js +158 -45
  22. package/dist/src/commands/env.js.map +1 -1
  23. package/dist/src/commands/functions.js +7 -1
  24. package/dist/src/commands/functions.js.map +1 -1
  25. package/dist/src/commands/init.js +2 -1
  26. package/dist/src/commands/init.js.map +1 -1
  27. package/dist/src/commands/integrations.js +14 -2
  28. package/dist/src/commands/integrations.js.map +1 -1
  29. package/dist/src/commands/prompts.js +4 -0
  30. package/dist/src/commands/prompts.js.map +1 -1
  31. package/dist/src/commands/scripts.js +1 -1
  32. package/dist/src/commands/scripts.js.map +1 -1
  33. package/dist/src/commands/sync-app-settings.d.ts +25 -7
  34. package/dist/src/commands/sync-app-settings.js +81 -20
  35. package/dist/src/commands/sync-app-settings.js.map +1 -1
  36. package/dist/src/commands/sync.d.ts +107 -9
  37. package/dist/src/commands/sync.js +649 -300
  38. package/dist/src/commands/sync.js.map +1 -1
  39. package/dist/src/commands/users.js +77 -2
  40. package/dist/src/commands/users.js.map +1 -1
  41. package/dist/src/lib/api-client.d.ts +161 -5
  42. package/dist/src/lib/api-client.js +210 -49
  43. package/dist/src/lib/api-client.js.map +1 -1
  44. package/dist/src/lib/app-settings-descriptor.d.ts +9 -1
  45. package/dist/src/lib/app-settings-descriptor.js +22 -10
  46. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  47. package/dist/src/lib/auth-flow.d.ts +41 -1
  48. package/dist/src/lib/auth-flow.js +45 -16
  49. package/dist/src/lib/auth-flow.js.map +1 -1
  50. package/dist/src/lib/child-apps-local.d.ts +184 -0
  51. package/dist/src/lib/child-apps-local.js +282 -0
  52. package/dist/src/lib/child-apps-local.js.map +1 -0
  53. package/dist/src/lib/ci-session-request.d.ts +22 -0
  54. package/dist/src/lib/ci-session-request.js +51 -0
  55. package/dist/src/lib/ci-session-request.js.map +1 -0
  56. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +4 -1
  57. package/dist/src/lib/codegen-shared/generatedFiles.js +19 -13
  58. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
  59. package/dist/src/lib/config-object-descriptor.js +5 -4
  60. package/dist/src/lib/config-object-descriptor.js.map +1 -1
  61. package/dist/src/lib/config-payload.js +2 -3
  62. package/dist/src/lib/config-payload.js.map +1 -1
  63. package/dist/src/lib/config-surface.d.ts +2 -1
  64. package/dist/src/lib/config-surface.js +7 -28
  65. package/dist/src/lib/config-surface.js.map +1 -1
  66. package/dist/src/lib/credentials-store.d.ts +17 -2
  67. package/dist/src/lib/credentials-store.js +72 -6
  68. package/dist/src/lib/credentials-store.js.map +1 -1
  69. package/dist/src/lib/document-export-lookups.d.ts +31 -0
  70. package/dist/src/lib/document-export-lookups.js +53 -0
  71. package/dist/src/lib/document-export-lookups.js.map +1 -0
  72. package/dist/src/lib/document-export-permissions.d.ts +7 -5
  73. package/dist/src/lib/document-export-permissions.js +7 -5
  74. package/dist/src/lib/document-export-permissions.js.map +1 -1
  75. package/dist/src/lib/env-resolver-core.d.ts +69 -1
  76. package/dist/src/lib/env-resolver-core.js +137 -20
  77. package/dist/src/lib/env-resolver-core.js.map +1 -1
  78. package/dist/src/lib/env-resolver.d.ts +14 -2
  79. package/dist/src/lib/env-resolver.js +32 -10
  80. package/dist/src/lib/env-resolver.js.map +1 -1
  81. package/dist/src/lib/function-run.d.ts +4 -1
  82. package/dist/src/lib/function-run.js +24 -4
  83. package/dist/src/lib/function-run.js.map +1 -1
  84. package/dist/src/lib/function-sync.d.ts +5 -2
  85. package/dist/src/lib/function-sync.js +7 -4
  86. package/dist/src/lib/function-sync.js.map +1 -1
  87. package/dist/src/lib/generated-config-surfaces.d.ts +49 -52
  88. package/dist/src/lib/generated-config-surfaces.js +211 -140
  89. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  90. package/dist/src/lib/generated-sdk-types.d.ts +1 -1
  91. package/dist/src/lib/generated-sdk-types.js +1 -1
  92. package/dist/src/lib/generated-sdk-types.js.map +1 -1
  93. package/dist/src/lib/init-adopt.js +12 -3
  94. package/dist/src/lib/init-adopt.js.map +1 -1
  95. package/dist/src/lib/local-state.d.ts +17 -1
  96. package/dist/src/lib/local-state.js +94 -15
  97. package/dist/src/lib/local-state.js.map +1 -1
  98. package/dist/src/lib/local-test-cases.d.ts +5 -2
  99. package/dist/src/lib/local-test-cases.js +7 -4
  100. package/dist/src/lib/local-test-cases.js.map +1 -1
  101. package/dist/src/lib/log-inspection.d.ts +25 -0
  102. package/dist/src/lib/log-inspection.js +24 -0
  103. package/dist/src/lib/log-inspection.js.map +1 -1
  104. package/dist/src/lib/logout-admin-session.d.ts +2 -1
  105. package/dist/src/lib/logout-admin-session.js +7 -1
  106. package/dist/src/lib/logout-admin-session.js.map +1 -1
  107. package/dist/src/lib/pull-write.d.ts +31 -0
  108. package/dist/src/lib/pull-write.js +49 -0
  109. package/dist/src/lib/pull-write.js.map +1 -0
  110. package/dist/src/lib/root-import-decision.d.ts +59 -0
  111. package/dist/src/lib/root-import-decision.js +95 -0
  112. package/dist/src/lib/root-import-decision.js.map +1 -0
  113. package/dist/src/lib/scope-request.d.ts +69 -0
  114. package/dist/src/lib/scope-request.js +188 -0
  115. package/dist/src/lib/scope-request.js.map +1 -0
  116. package/dist/src/lib/session-id.d.ts +9 -0
  117. package/dist/src/lib/session-id.js +28 -0
  118. package/dist/src/lib/session-id.js.map +1 -0
  119. package/dist/src/lib/snapshots.d.ts +17 -1
  120. package/dist/src/lib/snapshots.js +50 -2
  121. package/dist/src/lib/snapshots.js.map +1 -1
  122. package/dist/src/lib/sync-paths.d.ts +35 -0
  123. package/dist/src/lib/sync-paths.js +57 -5
  124. package/dist/src/lib/sync-paths.js.map +1 -1
  125. package/dist/src/lib/transient-retry.d.ts +34 -0
  126. package/dist/src/lib/transient-retry.js +57 -0
  127. package/dist/src/lib/transient-retry.js.map +1 -0
  128. package/dist/src/types/index.d.ts +21 -4
  129. package/package.json +4 -3
@@ -94,9 +94,8 @@ export function writableFieldNames(table, mode) {
94
94
  * The field names the server PERSISTS for this table in `mode`: the writable
95
95
  * fields, plus the `deprecated` classifications — "still writable, superseded
96
96
  * by another field" is what that kind means (`types.ts`), so a superseded key
97
- * a handler still honors (`passkeyRpId`, or a flat chat key such as
98
- * `systemPrompt` under `[[configs]]`, #3626) belongs in every
99
- * accepted set, and a field that is NOT writable belongs in none of them.
97
+ * a handler still honors (`passkeyRpId`) belongs in every accepted set, and a
98
+ * field that is NOT writable belongs in none of them.
100
99
  *
101
100
  * Stated once here because three consumers need the same answer: the generated
102
101
  * request schemas, `PUT /settings`'s write allow-list, and the guards.
@@ -402,8 +401,9 @@ export function acceptedGroupTomlKeys(table, group) {
402
401
  * is therefore an unknown key rather than one the payload builder silently
403
402
  * ignores (SO3626-013) — the builder reads a grouped field only from
404
403
  * `source[group][tomlKey]`, so accepting it here would drop the author's value
405
- * without a word. The nine deprecated flat chat keys stay accepted through
406
- * their `tomlOnlyKeys` declarations, which is what keeps old files pushing.
404
+ * without a word. A key whose root spelling was retired while it moved into a
405
+ * group (the flat chat keys, #3642) is refused the same way, with the guidance
406
+ * `RETIRED_TOML_SPELLINGS` states.
407
407
  */
408
408
  export function acceptedTomlKeys(table) {
409
409
  return new Set([
@@ -2344,9 +2344,11 @@ export const RETIRED_CONFIG_KEYS = {
2344
2344
  "names.",
2345
2345
  },
2346
2346
  // #2884 — email sign-in became ONE flow, so it has ONE setting. Both keys
2347
- // stay DECLARED in `models.yaml` and are mirrored on every write of
2348
- // `emailSignInEnabled`, but neither is authorable any more: a file that
2349
- // still carries one is asking for a method choice that no longer exists.
2347
+ // stay DECLARED in `models.yaml` as hidden attributes (#3993): never
2348
+ // written, never echoed, refused by `config push`, the tenant PUT and the
2349
+ // admin API alike, and read only by the fallback for a row that stores no
2350
+ // `emailSignInEnabled`. A file or body that still carries one is asking
2351
+ // for a method choice that no longer exists.
2350
2352
  magicLinkEnabled: {
2351
2353
  toml: "`magicLinkEnabled` is no longer authored in TOML (#2884). Email " +
2352
2354
  "sign-in is one flow — one request sends one email carrying a code " +
@@ -2602,6 +2604,47 @@ export const RETIRED_CONFIG_KEYS = {
2602
2604
  export function retiredConfigKey(prefix, key) {
2603
2605
  return RETIRED_CONFIG_KEYS[prefix]?.[key] ?? null;
2604
2606
  }
2607
+ // #3642 — the pre-#3626 flat spelling of one chat setting. The six keys an
2608
+ // agent's model round shares (`AGENT_CONFIG_KEYS`) also name the agent block.
2609
+ // The names are written out rather than read from `prompt-kinds.ts`, which the
2610
+ // vendored artifact places after this module.
2611
+ function flatChatKeySpelling(key, sharedWithAgent) {
2612
+ return {
2613
+ toml: `\`${key}\` is no longer authored flat under \`[[configs]]\` (#3642). ` +
2614
+ "Chat settings live in the entry's `[configs.chat]` block" +
2615
+ (sharedWithAgent ? " (`[configs.agent]` on an agent prompt)" : "") +
2616
+ ": move the line into that block and push again. `config pull` " +
2617
+ "rewrites a file whose prompt already exists on the server.",
2618
+ };
2619
+ }
2620
+ /**
2621
+ * Spellings retired from TOML while the key itself stays live on the wire,
2622
+ * keyed like `RETIRED_CONFIG_KEYS`. The request side never reads this map: a
2623
+ * body that sends one of these keys is a body the schema accepts.
2624
+ */
2625
+ export const RETIRED_TOML_SPELLINGS = {
2626
+ // #3642 — the nine chat keys at the prompt `[[configs]]` root. The admin
2627
+ // API's create and update bodies still carry them flat; only the TOML
2628
+ // grouping (#3626) moved them under `[configs.chat]`.
2629
+ configs: {
2630
+ systemPrompt: flatChatKeySpelling("systemPrompt", true),
2631
+ userPromptTemplate: flatChatKeySpelling("userPromptTemplate", false),
2632
+ temperature: flatChatKeySpelling("temperature", true),
2633
+ topP: flatChatKeySpelling("topP", true),
2634
+ maxTokens: flatChatKeySpelling("maxTokens", true),
2635
+ outputFormat: flatChatKeySpelling("outputFormat", false),
2636
+ outputSchema: flatChatKeySpelling("outputSchema", false),
2637
+ reasoningEffort: flatChatKeySpelling("reasoningEffort", true),
2638
+ reasoningBudget: flatChatKeySpelling("reasoningBudget", true),
2639
+ },
2640
+ };
2641
+ /**
2642
+ * The TOML guidance for `key` under `prefix`: a fully retired key's, else a
2643
+ * retired spelling's, else null when the key is simply unknown.
2644
+ */
2645
+ export function retiredTomlKey(prefix, key) {
2646
+ return (retiredConfigKey(prefix, key) ?? RETIRED_TOML_SPELLINGS[prefix]?.[key] ?? null);
2647
+ }
2605
2648
  // ── src/config-surface/function-grants.ts ────────────────────────────────
2606
2649
  /**
2607
2650
  * The capability grammar for server functions — #3182 phase 1, rewritten by
@@ -4775,7 +4818,12 @@ export function checkCronTriggerEntry(entry) {
4775
4818
  * all read this one copy, so a refusal at push and a refusal at execution
4776
4819
  * cannot disagree.
4777
4820
  *
4778
- * Provider facts this encodes:
4821
+ * What this encodes is each provider's SPELLING, per model family — never
4822
+ * which values a particular model accepts (#4147). A value the spelling can
4823
+ * carry is sent, and a model that does not support it is refused by the
4824
+ * provider, whose answer the run reports. A per-model table of accepted levels
4825
+ * and floors went stale with each model release and refused or admitted the
4826
+ * wrong values.
4779
4827
  *
4780
4828
  * - OpenRouter takes a unified `reasoning` block: `{ effort }`,
4781
4829
  * `{ max_tokens }`, or `{ enabled: false }` to decline it. `max_tokens` is an
@@ -4788,13 +4836,13 @@ export function checkCronTriggerEntry(entry) {
4788
4836
  * is refused by OpenRouter and surfaces as a failed execution rather than a
4789
4837
  * silent drop.
4790
4838
  * - Gemini 3.x expresses thinking as a LEVEL
4791
- * (`thinkingConfig.thinkingLevel`) and cannot turn it off; `thinkingBudget`
4792
- * is accepted there only for backward compatibility and is translated to a
4793
- * level rather than honored as a bound, so a numeric budget is refused with
4794
- * a pointer at `reasoningEffort`.
4839
+ * (`thinkingConfig.thinkingLevel`), and the level spelling has no "off"
4840
+ * value, so `none` has nothing to translate to. `thinkingBudget` is accepted
4841
+ * there only for backward compatibility and is translated to a level rather
4842
+ * than honored as a bound, so a numeric budget is refused with a pointer at
4843
+ * `reasoningEffort`.
4795
4844
  * - Gemini 2.5 expresses it as a numeric BUDGET
4796
- * (`thinkingConfig.thinkingBudget`); `0` turns thinking off on Flash and
4797
- * Flash-Lite, while Pro has a floor of 128 and answers 400 for less.
4845
+ * (`thinkingConfig.thinkingBudget`); `none` is a budget of `0`.
4798
4846
  * - Gemini 2.0 and earlier have no thinking control at all.
4799
4847
  */
4800
4848
  /** The provider-neutral effort levels a config may state. */
@@ -4805,8 +4853,6 @@ export const REASONING_EFFORTS = [
4805
4853
  "medium",
4806
4854
  "high",
4807
4855
  ];
4808
- /** The smallest budget Gemini 2.5 Pro accepts; it cannot stop thinking. */
4809
- export const GEMINI_PRO_MIN_THINKING_BUDGET = 128;
4810
4856
  export function geminiReasoningFamily(model) {
4811
4857
  const match = /gemini-(\d+)(?:[.-](\d+))?/i.exec(model || "");
4812
4858
  if (!match)
@@ -4821,10 +4867,6 @@ export function geminiReasoningFamily(model) {
4821
4867
  return "budget";
4822
4868
  return "none";
4823
4869
  }
4824
- /** Gemini Pro: the tier that cannot stop thinking in either family. */
4825
- export function isGeminiProModel(model) {
4826
- return /(^|[-_/.])pro($|[-_/.])/i.test(model || "");
4827
- }
4828
4870
  /** Is EITHER reasoning key stated on this config? */
4829
4871
  export function hasPromptReasoning(input) {
4830
4872
  return (normalizeEffort(input.reasoningEffort) !== null ||
@@ -4908,7 +4950,6 @@ function openRouterDirective(effort, budget) {
4908
4950
  }
4909
4951
  function geminiResolution(model, effort, budget) {
4910
4952
  const family = geminiReasoningFamily(model);
4911
- const isPro = isGeminiProModel(model);
4912
4953
  if (family === "none") {
4913
4954
  return {
4914
4955
  ok: false,
@@ -4931,15 +4972,10 @@ function geminiResolution(model, effort, budget) {
4931
4972
  if (effort === "none") {
4932
4973
  return {
4933
4974
  ok: false,
4934
- error: `Gemini model '${model}' cannot turn thinking off. The lowest level it ` +
4935
- `accepts is '${isPro ? "low" : "minimal"}'.`,
4936
- };
4937
- }
4938
- if (isPro && (effort === "minimal" || effort === "medium")) {
4939
- return {
4940
- ok: false,
4941
- error: `Gemini Pro model '${model}' accepts only 'low' or 'high' as a ` +
4942
- `thinking level; '${effort}' is a Flash-only level.`,
4975
+ error: `Gemini model '${model}' expresses reasoning as a LEVEL, which has no ` +
4976
+ "'none' value. Use reasoningEffort " +
4977
+ `(${REASONING_EFFORTS.filter((e) => e !== "none").join(", ")}); the ` +
4978
+ "provider's model documentation lists which levels this model accepts.",
4943
4979
  };
4944
4980
  }
4945
4981
  return {
@@ -4960,14 +4996,6 @@ function geminiResolution(model, effort, budget) {
4960
4996
  };
4961
4997
  }
4962
4998
  const resolved = effort === "none" ? 0 : budget;
4963
- if (isPro && resolved < GEMINI_PRO_MIN_THINKING_BUDGET) {
4964
- return {
4965
- ok: false,
4966
- error: `Gemini Pro model '${model}' cannot turn thinking off: its smallest ` +
4967
- `thinking budget is ${GEMINI_PRO_MIN_THINKING_BUDGET} tokens, and ` +
4968
- `${resolved} is refused by the provider.`,
4969
- };
4970
- }
4971
4999
  return {
4972
5000
  ok: true,
4973
5001
  directive: {
@@ -5007,12 +5035,16 @@ function geminiResolution(model, effort, budget) {
5007
5035
  */
5008
5036
  export const PROMPT_KINDS = ["chat", "decisions", "agent"];
5009
5037
  /**
5010
- * The nine chat settings that existed before `[configs.chat]` did. Only these
5011
- * keep the deprecated FLAT spelling (#3642): a key added to the block later was
5012
- * never written flat by any file, so it has none (the `questions` posture,
5013
- * SO3626-013).
5038
+ * The settings that describe a CHAT COMPLETION and nothing else. They are
5039
+ * authored under `[configs.chat]` and only there: the pre-#3626 flat spelling
5040
+ * of the first nine is retired and refused at push (#3642,
5041
+ * `RETIRED_TOML_SPELLINGS`).
5042
+ *
5043
+ * #3801 — `strictOutput`, the opt-in that sends `[prompt].outputSchema` as a
5044
+ * strict `json_schema` on OpenRouter (`prompt-strict-output.ts`). Not an agent
5045
+ * key (§D1: an agent has no output schema), so the agent arm refuses it.
5014
5046
  */
5015
- export const LEGACY_FLAT_CHAT_KEYS = [
5047
+ export const CHAT_CONFIG_KEYS = [
5016
5048
  "systemPrompt",
5017
5049
  "userPromptTemplate",
5018
5050
  "temperature",
@@ -5022,18 +5054,6 @@ export const LEGACY_FLAT_CHAT_KEYS = [
5022
5054
  "outputSchema",
5023
5055
  "reasoningEffort",
5024
5056
  "reasoningBudget",
5025
- ];
5026
- /**
5027
- * The settings that describe a CHAT COMPLETION and nothing else. They are
5028
- * authored under `[configs.chat]`; the flat spelling of the nine legacy keys
5029
- * is deprecated (#3642).
5030
- *
5031
- * #3801 — `strictOutput`, the opt-in that sends `[prompt].outputSchema` as a
5032
- * strict `json_schema` on OpenRouter (`prompt-strict-output.ts`). Not an agent
5033
- * key (§D1: an agent has no output schema), so the agent arm refuses it.
5034
- */
5035
- export const CHAT_CONFIG_KEYS = [
5036
- ...LEGACY_FLAT_CHAT_KEYS,
5037
5057
  "strictOutput",
5038
5058
  ];
5039
5059
  /** The settings that describe a DECISIONS request. */
@@ -5469,46 +5489,6 @@ export function resolveDecisionsRunQuestions(questions, runCriteria) {
5469
5489
  }
5470
5490
  return { ok: true, questions: resolved };
5471
5491
  }
5472
- /**
5473
- * Move the deprecated flat chat keys of one `[[configs]]` entry under `chat`
5474
- * — #3626 §4, the deprecated-TOML-key pattern blob buckets used until #3996
5475
- * retired theirs, made reusable.
5476
- *
5477
- * Push keeps accepting the nine keys flat so no existing file breaks, and pull
5478
- * rewrites them, so one pull-then-push migrates a file. A key present in BOTH
5479
- * spellings is not merged: the grouped value is left standing and the key is
5480
- * reported in `conflicts`, which the caller turns into a refusal naming the
5481
- * entry. Nothing else in the entry is touched — `providerConfig` is
5482
- * provider-keyed rather than chat-keyed (D3626-002) and `questions` has no flat
5483
- * spelling at all (SO3626-013).
5484
- */
5485
- export function hoistDeprecatedChatKeys(entry) {
5486
- if (!isPlainObject(entry)) {
5487
- return { entry: {}, moved: [], conflicts: [] };
5488
- }
5489
- const out = { ...entry };
5490
- const existingGroup = isPlainObject(out.chat) ? { ...out.chat } : undefined;
5491
- const group = existingGroup ?? {};
5492
- const moved = [];
5493
- const conflicts = [];
5494
- // #3801 — only the legacy keys have a flat spelling to hoist; `strictOutput`
5495
- // at the root is an unknown key naming its block.
5496
- for (const key of LEGACY_FLAT_CHAT_KEYS) {
5497
- if (!(key in out))
5498
- continue;
5499
- if (existingGroup && key in existingGroup) {
5500
- conflicts.push(key);
5501
- delete out[key];
5502
- continue;
5503
- }
5504
- group[key] = out[key];
5505
- delete out[key];
5506
- moved.push(key);
5507
- }
5508
- if (existingGroup || moved.length > 0)
5509
- out.chat = group;
5510
- return { entry: out, moved: moved.sort(), conflicts: conflicts.sort() };
5511
- }
5512
5492
  // ── src/config-surface/prompt-strict-output.ts ───────────────────────────
5513
5493
  /**
5514
5494
  * Strict output for a chat config — issue #3801 (project `agents`, §D6).
@@ -5719,16 +5699,20 @@ export const AGENT_ERROR_CODES = [
5719
5699
  "AGENT_ROUND_EMPTY",
5720
5700
  ];
5721
5701
  /**
5722
- * The platform maximums. An agent may lower `maxSteps` and `waitLimitSeconds`,
5723
- * never raise them; the tool and event counts bound what one declaration can
5724
- * make every turn carry (principle 2).
5702
+ * The platform maximums. An agent may lower `maxSteps`, `waitLimitSeconds`
5703
+ * and `maxRowBytes`, never raise them; the tool and event counts bound what
5704
+ * one declaration can make every turn carry (principle 2).
5725
5705
  */
5726
5706
  export const AGENT_LIMITS = {
5727
5707
  maxSteps: 25,
5728
5708
  waitLimitSeconds: 604800,
5709
+ /** The JSON bytes of one session-document row a turn writes from model or tool output. */
5710
+ maxRowBytes: 262144,
5729
5711
  tools: 64,
5730
5712
  events: 64,
5731
5713
  };
5714
+ /** The smallest row ceiling an agent may declare: room for a call's own columns. */
5715
+ export const AGENT_ROW_BYTES_FLOOR = 1024;
5732
5716
  /**
5733
5717
  * A tool or event name: the intersection of OpenRouter's and Gemini's
5734
5718
  * function-name rules, so one declaration maps onto either provider.
@@ -5741,6 +5725,7 @@ const AGENT_TOP_LEVEL_KEYS = [
5741
5725
  "answeredBy",
5742
5726
  "maxSteps",
5743
5727
  "waitLimitSeconds",
5728
+ "maxRowBytes",
5744
5729
  "turnContext",
5745
5730
  "history",
5746
5731
  "tools",
@@ -5831,13 +5816,13 @@ function agentSchemaError(value, path) {
5831
5816
  return agentInvalid(path, `must be a table (a JSON Schema object); found ${found}. Write it as ` +
5832
5817
  "TOML tables, or as an object inside a block written as one JSON string");
5833
5818
  }
5834
- function agentIntegerInRange(value, path, max, out) {
5819
+ function agentIntegerInRange(value, path, max, out, min = 1) {
5835
5820
  if (typeof value !== "number" || !Number.isInteger(value)) {
5836
- out.push(agentInvalid(path, `must be an integer from 1 to ${max}`));
5821
+ out.push(agentInvalid(path, `must be an integer from ${min} to ${max}`));
5837
5822
  return;
5838
5823
  }
5839
- if (value < 1 || value > max) {
5840
- out.push(agentInvalid(path, `must be from 1 to ${max} (the platform maximum); found ${value}`));
5824
+ if (value < min || value > max) {
5825
+ out.push(agentInvalid(path, `must be from ${min} to ${max} (the platform maximum); found ${value}`));
5841
5826
  }
5842
5827
  }
5843
5828
  function checkAgentName(value, path, seen, what, out) {
@@ -5957,6 +5942,9 @@ function agentShapeRefusals(agent) {
5957
5942
  if (agent.waitLimitSeconds !== undefined) {
5958
5943
  agentIntegerInRange(agent.waitLimitSeconds, "waitLimitSeconds", AGENT_LIMITS.waitLimitSeconds, out);
5959
5944
  }
5945
+ if (agent.maxRowBytes !== undefined) {
5946
+ agentIntegerInRange(agent.maxRowBytes, "maxRowBytes", AGENT_LIMITS.maxRowBytes, out, AGENT_ROW_BYTES_FLOOR);
5947
+ }
5960
5948
  if (agent.turnContext !== undefined) {
5961
5949
  const turnContext = agent.turnContext;
5962
5950
  if (!agentIsPlainObject(turnContext)) {
@@ -6189,6 +6177,7 @@ export function normalizeAgentDeclaration(declaration) {
6189
6177
  answeredBy: source.answeredBy ?? "initiator",
6190
6178
  maxSteps: source.maxSteps ?? AGENT_LIMITS.maxSteps,
6191
6179
  waitLimitSeconds: source.waitLimitSeconds ?? AGENT_LIMITS.waitLimitSeconds,
6180
+ maxRowBytes: source.maxRowBytes ?? AGENT_LIMITS.maxRowBytes,
6192
6181
  turnContext: source.turnContext ?? null,
6193
6182
  history: source.history ?? null,
6194
6183
  tools: (source.tools ?? []).map((tool) => ({
@@ -6933,29 +6922,6 @@ const PROMPT_HANDLER = "src/admin-api.ts";
6933
6922
  * and output keys (`AGENT_CONFIG_KEYS`).
6934
6923
  */
6935
6924
  const SHARED_WITH_AGENT = ["chat", "agent"];
6936
- /**
6937
- * #3626 §4 — the nine chat keys, still accepted FLAT under `[[configs]]`.
6938
- *
6939
- * The deprecated-TOML-key pattern blob buckets used until #3996 retired
6940
- * theirs: declared `deprecated`, so
6941
- * `config push` keeps taking a file written before the `[configs.chat]` block
6942
- * existed, while `config pull` never writes the spelling again. One
6943
- * pull-then-push migrates a file. `hoistDeprecatedChatKeys` moves them into the
6944
- * group before the payload is built; rejecting the flat spelling outright is
6945
- * #3642. #3801 — only the nine: a chat key added later (`strictOutput`) was
6946
- * never written flat, so it has no deprecated spelling to accept.
6947
- */
6948
- const DEPRECATED_FLAT_CHAT_KEYS = Object.fromEntries(LEGACY_FLAT_CHAT_KEYS.map((key) => [
6949
- key,
6950
- {
6951
- kind: "deprecated",
6952
- note: `#3626 — the pre-kind spelling of \`[configs.chat].${key}\`. Still ` +
6953
- "accepted flat so no existing prompt file breaks (push hoists it " +
6954
- "into the block and warns); `config pull` writes only the grouped " +
6955
- "spelling, so one pull-then-push migrates the file. Rejecting the " +
6956
- "flat spelling is #3642.",
6957
- },
6958
- ]));
6959
6925
  export const PROMPT_SURFACE = {
6960
6926
  label: "prompt",
6961
6927
  tables: [
@@ -7165,7 +7131,7 @@ export const PROMPT_SURFACE = {
7165
7131
  note: "#3626 — the chat-completion settings of a `kind = \"chat\"` " +
7166
7132
  "prompt: the nine keys that describe a chat call and nothing " +
7167
7133
  "else. Authored under `[configs.chat]`; the flat spelling is " +
7168
- "accepted as deprecated (#3642) and rewritten by `config pull`.",
7134
+ "retired (#3642) and refused at push with `RETIRED_TOML_SPELLINGS`.",
7169
7135
  },
7170
7136
  decisions: {
7171
7137
  note: "#3626 — the settings of a `kind = \"decisions\"` prompt: the " +
@@ -7450,8 +7416,6 @@ export const PROMPT_SURFACE = {
7450
7416
  "active entry; push enacts it through the activate endpoint " +
7451
7417
  "(activatePromptConfig), never as a config-body key.",
7452
7418
  },
7453
- // #3626 §4 — the nine chat keys in their pre-kind FLAT spelling.
7454
- ...DEPRECATED_FLAT_CHAT_KEYS,
7455
7419
  },
7456
7420
  responseOnlyKeys: {},
7457
7421
  },
@@ -8278,10 +8242,12 @@ export const CRON_TRIGGER_SURFACE = {
8278
8242
  * `blob-buckets/<key>.toml` carries a single `[bucket]` table.
8279
8243
  *
8280
8244
  * `ttlTier` is `writableOn: ["create"]`: the update handler does not read it, so
8281
- * the retention tier is fixed at creation. `preset` and `ruleSetId` are the two
8245
+ * the retention tier is fixed at creation. `preset` and the rule set are the two
8282
8246
  * halves of the access model (#1020), and the only access keys: at most one may
8283
- * change per request, which is the controller's rule and stays there. The
8284
- * pre-#1020 `accessPolicy` spelling is a retired key (#3996, `retired-keys.ts`).
8247
+ * change per request, which is the controller's rule and stays there. The rule
8248
+ * set is authored by name (`ruleSetName`) and sent as `ruleSetId`, as the type
8249
+ * configs do (#4116); the id spelling in TOML is deprecated. The pre-#1020
8250
+ * `accessPolicy` spelling is a retired key (#3996, `retired-keys.ts`).
8285
8251
  */
8286
8252
  const BLOB_BUCKET_HANDLER = "src/app-api/controllers/blob-buckets-controller.ts";
8287
8253
  export const BLOB_BUCKET_SURFACE = {
@@ -8330,12 +8296,14 @@ export const BLOB_BUCKET_SURFACE = {
8330
8296
  },
8331
8297
  {
8332
8298
  field: "ruleSetId",
8333
- tomlKey: "ruleSetId",
8299
+ tomlKey: "ruleSetName",
8334
8300
  type: "string",
8335
8301
  emit: "whenSet",
8336
8302
  writableOn: BOTH,
8337
- // Existence-checked against AccessRuleSet; mutually exclusive with a
8338
- // preset change in the same request.
8303
+ // Authored as a name, sent as an id (#4116), so a tree copied into
8304
+ // another app binds that app's rule set. Existence-checked against
8305
+ // AccessRuleSet; mutually exclusive with a preset change in the same
8306
+ // request.
8339
8307
  validation: handledBy(BLOB_BUCKET_HANDLER, "BlobBucketsController", "apply"),
8340
8308
  },
8341
8309
  ],
@@ -8385,6 +8353,14 @@ export const BLOB_BUCKET_SURFACE = {
8385
8353
  note: "The bucket key. `config pull` writes it for readability; push takes " +
8386
8354
  "the identity from the file name and attaches `bucketKey` itself.",
8387
8355
  },
8356
+ ruleSetId: {
8357
+ kind: "deprecated",
8358
+ note: "The id spelling of the rule-set reference (#4116). An id names a " +
8359
+ "rule set in one app, so a copied tree cannot resolve it; " +
8360
+ "`ruleSetName` is the authored key. Still accepted on push, with " +
8361
+ "an advisory line, and `config pull` rewrites the file to " +
8362
+ "`ruleSetName`. Retiring it is a later change of its own.",
8363
+ },
8388
8364
  },
8389
8365
  responseOnlyKeys: {},
8390
8366
  },
@@ -9923,6 +9899,33 @@ export const APP_SETTINGS_SURFACE = {
9923
9899
  // offline work around it (`parseLargeDocumentWindowSetting`).
9924
9900
  validation: handledBy(SETTINGS_HANDLER, "SettingsController", "apply"),
9925
9901
  },
9902
+ {
9903
+ field: "rootDocumentFormat",
9904
+ tomlKey: "rootDocumentFormat",
9905
+ type: "number",
9906
+ // Whenever the app chose one. An app that never did mints legacy
9907
+ // roots, and a pulled file should not grow a key for it (#4195).
9908
+ emit: "whenSet",
9909
+ writableOn: UPDATE_ONLY,
9910
+ // 1, 2 or cleared; anything else is refused, because a root's format
9911
+ // is permanent and the mint must never guess
9912
+ // (`parseRootDocumentFormatSetting`).
9913
+ validation: handledBy(SETTINGS_HANDLER, "SettingsController", "apply"),
9914
+ },
9915
+ {
9916
+ field: "protected",
9917
+ tomlKey: "protected",
9918
+ type: "boolean",
9919
+ // Always: a pulled file states whether the app is live with real
9920
+ // users, rather than leaving it to the absence of a key (#3886).
9921
+ emit: "always",
9922
+ writableOn: UPDATE_ONLY,
9923
+ // Strict boolean, and only the app's console owner or a super-admin
9924
+ // may CHANGE it; a body carrying the stored value is a no-op for
9925
+ // anyone the route admits (`resolveProtectedFlagWrite`,
9926
+ // `src/services/protected-app.ts`).
9927
+ validation: handledBy(SETTINGS_HANDLER, "SettingsController", "apply"),
9928
+ },
9926
9929
  ],
9927
9930
  notExposed: {
9928
9931
  appId: {
@@ -9937,6 +9940,58 @@ export const APP_SETTINGS_SURFACE = {
9937
9940
  kind: "server-owned",
9938
9941
  note: "Admin who created the app; assigned server-side.",
9939
9942
  },
9943
+ // Child apps: lineage is set when a child is created and never
9944
+ // changes; expiry and activity are written by the server. The admin
9945
+ // update route refuses a changed value of any of these.
9946
+ parentAppId: {
9947
+ kind: "server-owned",
9948
+ note: "A child's parent app; set at creation, never authored.",
9949
+ },
9950
+ childSlug: {
9951
+ kind: "server-owned",
9952
+ note: "A child's slug under its parent; set at creation, never authored.",
9953
+ },
9954
+ parentSlugKey: {
9955
+ kind: "server-owned",
9956
+ note: "The `<parentAppId>#<slug>` uniqueness key of a child.",
9957
+ },
9958
+ ownerAdminId: {
9959
+ kind: "server-owned",
9960
+ note: "The admin who owns a child; the creator, set at creation.",
9961
+ },
9962
+ branch: {
9963
+ kind: "server-owned",
9964
+ note: "The git branch a child was created from; set at creation.",
9965
+ },
9966
+ idleDays: {
9967
+ kind: "server-owned",
9968
+ note: "Days of inactivity before a child expires; set at creation.",
9969
+ },
9970
+ expiresAt: {
9971
+ kind: "server-owned",
9972
+ note: "When a child expires; maintained by the server.",
9973
+ },
9974
+ warnedForExpiresAt: {
9975
+ kind: "server-owned",
9976
+ note: "The expiry a child's owner was last warned about.",
9977
+ },
9978
+ deletingAt: {
9979
+ kind: "server-owned",
9980
+ note: "When the expiry sweep claimed a child for deletion.",
9981
+ },
9982
+ previewOrigins: {
9983
+ kind: "server-owned",
9984
+ note: "A child's preview origins; written only by the preview-origins " +
9985
+ "route, so sync never sees it.",
9986
+ },
9987
+ childPartition: {
9988
+ kind: "server-owned",
9989
+ note: "The constant partition of the child-only expiry index.",
9990
+ },
9991
+ lastActivityAt: {
9992
+ kind: "server-owned",
9993
+ note: "When the app last saw counted activity; written by the server.",
9994
+ },
9940
9995
  passkeyRpId: {
9941
9996
  kind: "server-owned",
9942
9997
  note: "RETIRED from the write surface by #2891, superseded by " +
@@ -9970,15 +10025,17 @@ export const APP_SETTINGS_SURFACE = {
9970
10025
  note: "RETIRED from the write surface by #2884, superseded by " +
9971
10026
  "`emailSignInEnabled`. Email sign-in is ONE flow — one request, " +
9972
10027
  "one email carrying a code and (when a link can be issued) a " +
9973
- "link — so there is no method to enable separately. The " +
9974
- "attribute stays declared and is MIRRORED on every write of " +
9975
- "`emailSignInEnabled`, so a row read by an un-migrated consumer " +
9976
- "still matches behavior.",
10028
+ "link — so there is no method to enable separately. Hidden " +
10029
+ "since #3993: never written, never echoed, refused on write; " +
10030
+ "read only by the email sign-in fallback for a row that stores " +
10031
+ "no `emailSignInEnabled`.",
9977
10032
  },
9978
10033
  otpEnabled: {
9979
10034
  kind: "server-owned",
9980
10035
  note: "The other half of the retired pair (#2884); superseded by " +
9981
- "`emailSignInEnabled` and mirrored the same way.",
10036
+ "`emailSignInEnabled`. Hidden since #3993 the same way: never " +
10037
+ "written, never echoed, refused on write; read only by the " +
10038
+ "email sign-in fallback.",
9982
10039
  },
9983
10040
  redirectUris: {
9984
10041
  kind: "server-owned",
@@ -10360,6 +10417,20 @@ export const GENERATED_CONFIG_MODEL_FIELDS = {
10360
10417
  "memberInvitationsEnabled",
10361
10418
  "memberInvitationLimit",
10362
10419
  "largeDocumentWindowDays",
10420
+ "rootDocumentFormat",
10421
+ "protected",
10422
+ "parentAppId",
10423
+ "childSlug",
10424
+ "parentSlugKey",
10425
+ "ownerAdminId",
10426
+ "branch",
10427
+ "idleDays",
10428
+ "expiresAt",
10429
+ "warnedForExpiresAt",
10430
+ "deletingAt",
10431
+ "previewOrigins",
10432
+ "childPartition",
10433
+ "lastActivityAt",
10363
10434
  "createdAt",
10364
10435
  "modifiedAt",
10365
10436
  ],