@opengeni/contracts 1.0.1 → 2.3.0-canary.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 (112) hide show
  1. package/dist/agent-authored-durable-text.d.ts +64 -0
  2. package/dist/atlassian.d.ts +1 -0
  3. package/dist/atlassian.js +14 -13
  4. package/dist/{chunk-Y3MLSLB4.js → chunk-3SIZGL3O.js} +42 -30
  5. package/dist/chunk-3SIZGL3O.js.map +1 -0
  6. package/dist/{chunk-JBCIY7QD.js → chunk-7RMTKFJW.js} +45 -22
  7. package/dist/chunk-7RMTKFJW.js.map +1 -0
  8. package/dist/{chunk-5UDNP7AO.js → chunk-MRWYRAS5.js} +56 -8
  9. package/dist/chunk-MRWYRAS5.js.map +1 -0
  10. package/dist/{chunk-LW7OH6CS.js → chunk-N6GRVXAJ.js} +6 -5
  11. package/dist/chunk-N6GRVXAJ.js.map +1 -0
  12. package/dist/{chunk-TZ6YEYN4.js → chunk-NVJMJWLL.js} +3 -1
  13. package/dist/chunk-NVJMJWLL.js.map +1 -0
  14. package/dist/chunk-PX3VCKAU.js +29 -0
  15. package/dist/chunk-PX3VCKAU.js.map +1 -0
  16. package/dist/{chunk-LSB7GRLG.js → chunk-TXTQIYCV.js} +15 -11
  17. package/dist/chunk-TXTQIYCV.js.map +1 -0
  18. package/dist/{chunk-NX5JNF4L.js → chunk-XW2RKNEU.js} +9410 -5799
  19. package/dist/chunk-XW2RKNEU.js.map +1 -0
  20. package/dist/{chunk-CADSX6UN.js → chunk-Y3KNXVTD.js} +2 -2
  21. package/dist/chunk-YBW5JSA3.js +251 -0
  22. package/dist/chunk-YBW5JSA3.js.map +1 -0
  23. package/dist/company-brain-governed-writes.d.ts +475 -0
  24. package/dist/company-brain.d.ts +398 -0
  25. package/dist/company-profile.d.ts +268 -0
  26. package/dist/connection-authority.d.ts +501 -0
  27. package/dist/connection-authority.js +364 -0
  28. package/dist/connection-authority.js.map +1 -0
  29. package/dist/connector-attachments.d.ts +95 -0
  30. package/dist/connector-attachments.js +51 -0
  31. package/dist/connector-attachments.js.map +1 -0
  32. package/dist/editable-artifact-codec-registry.d.ts +16 -7
  33. package/dist/editable-artifact-codec-registry.js +18 -8
  34. package/dist/editable-artifact-committed-transaction.d.ts +2 -2
  35. package/dist/editable-artifact-committed-transaction.js +2 -2
  36. package/dist/editable-artifact-live.d.ts +11 -12
  37. package/dist/editable-artifact-live.js +111 -46
  38. package/dist/editable-artifact-live.js.map +1 -1
  39. package/dist/editable-artifact-serialized-commit.d.ts +2 -1
  40. package/dist/editable-artifact-serialized-commit.js +9 -8
  41. package/dist/editable-artifact-versions.d.ts +20 -5
  42. package/dist/editable-artifact-versions.js +23 -5
  43. package/dist/editable-artifacts.d.ts +2 -0
  44. package/dist/editable-artifacts.js +51 -39
  45. package/dist/google-drive.d.ts +1 -0
  46. package/dist/google-drive.js +14 -13
  47. package/dist/google-drive.js.map +1 -1
  48. package/dist/governed-learning-activation.d.ts +154 -0
  49. package/dist/governed-learning-evaluator.d.ts +152 -0
  50. package/dist/index.d.ts +12426 -1313
  51. package/dist/index.js +855 -115
  52. package/dist/interaction.d.ts +68 -0
  53. package/dist/knowledge.d.ts +119 -0
  54. package/dist/organization-membership-lifecycle.d.ts +516 -0
  55. package/dist/permissions.d.ts +52 -0
  56. package/dist/personal-github.d.ts +319 -0
  57. package/dist/personal-github.js +209 -0
  58. package/dist/personal-github.js.map +1 -0
  59. package/dist/preference-registry.d.ts +17 -0
  60. package/dist/remember.d.ts +331 -0
  61. package/dist/sandbox-file-artifacts.d.ts +56 -0
  62. package/dist/sandbox-snapshots.d.ts +21 -0
  63. package/dist/slack-bot-scopes.d.ts +34 -14
  64. package/dist/slack-bot-scopes.js +5 -1
  65. package/dist/spreadsheet-artifact-commands.d.ts +2 -3
  66. package/dist/spreadsheet-artifact-commands.js +4 -2
  67. package/dist/spreadsheet-artifact-query.js +3 -2
  68. package/dist/task-notes.d.ts +42 -1
  69. package/dist/tool-result-spill.d.ts +16 -0
  70. package/dist/workspace-instruction-policies.d.ts +81 -0
  71. package/dist/workspace-learning-administration.d.ts +289 -0
  72. package/package.json +13 -1
  73. package/src/agent-authored-durable-text.ts +105 -0
  74. package/src/company-brain-governed-writes.ts +356 -0
  75. package/src/company-brain.ts +201 -0
  76. package/src/company-profile.ts +122 -1
  77. package/src/connection-authority.ts +413 -0
  78. package/src/connector-attachments.ts +327 -0
  79. package/src/editable-artifact-codec-registry.ts +55 -17
  80. package/src/editable-artifact-committed-transaction.ts +44 -31
  81. package/src/editable-artifact-live.ts +123 -57
  82. package/src/editable-artifact-serialized-commit.ts +2 -1
  83. package/src/editable-artifact-versions.ts +26 -5
  84. package/src/editable-artifacts.ts +2 -0
  85. package/src/governed-learning-activation.ts +191 -0
  86. package/src/governed-learning-evaluator.ts +176 -0
  87. package/src/index.ts +3148 -369
  88. package/src/interaction.ts +55 -1
  89. package/src/knowledge.ts +118 -6
  90. package/src/organization-membership-lifecycle.ts +330 -0
  91. package/src/permissions.ts +55 -0
  92. package/src/personal-github.ts +267 -0
  93. package/src/preference-registry.ts +17 -0
  94. package/src/remember.ts +242 -0
  95. package/src/sandbox-file-artifacts.ts +65 -0
  96. package/src/sandbox-snapshots.ts +78 -0
  97. package/src/slack-bot-scopes.ts +81 -9
  98. package/src/spreadsheet-artifact-commands.ts +12 -13
  99. package/src/task-notes.ts +14 -1
  100. package/src/tool-result-spill.ts +35 -0
  101. package/src/workspace-instruction-policies.ts +30 -0
  102. package/src/workspace-learning-administration.ts +88 -0
  103. package/dist/chunk-5UDNP7AO.js.map +0 -1
  104. package/dist/chunk-BVGIYW7D.js +0 -11
  105. package/dist/chunk-BVGIYW7D.js.map +0 -1
  106. package/dist/chunk-JBCIY7QD.js.map +0 -1
  107. package/dist/chunk-LSB7GRLG.js.map +0 -1
  108. package/dist/chunk-LW7OH6CS.js.map +0 -1
  109. package/dist/chunk-NX5JNF4L.js.map +0 -1
  110. package/dist/chunk-TZ6YEYN4.js.map +0 -1
  111. package/dist/chunk-Y3MLSLB4.js.map +0 -1
  112. /package/dist/{chunk-CADSX6UN.js.map → chunk-Y3KNXVTD.js.map} +0 -0
@@ -0,0 +1,267 @@
1
+ import { z } from "zod";
2
+
3
+ import { ConnectionMetadata } from "./index";
4
+
5
+ export const PERSONAL_GITHUB_PROVIDER_DOMAIN = "github.com" as const;
6
+ export const PERSONAL_GITHUB_PROVIDER_FAMILY = "github" as const;
7
+ export const PERSONAL_GITHUB_CREDENTIAL_ROLE = "opengeni_github_personal" as const;
8
+ export const PERSONAL_GITHUB_CONNECTION_SURFACE_ID = "github:personal" as const;
9
+ export const PERSONAL_GITHUB_REQUESTED_SCOPES = ["repo"] as const;
10
+ export const PERSONAL_GITHUB_AUTHORIZATION_URL =
11
+ "https://github.com/login/oauth/authorize" as const;
12
+ export const PERSONAL_GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token" as const;
13
+ export const PERSONAL_GITHUB_USER_URL = "https://api.github.com/user" as const;
14
+ export const PERSONAL_GITHUB_API_ORIGIN = "https://api.github.com" as const;
15
+ export const PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX = 100 as const;
16
+
17
+ export const PersonalGitHubRepositoryId = z.string().regex(/^[1-9]\d*$/u);
18
+ export type PersonalGitHubRepositoryId = z.infer<typeof PersonalGitHubRepositoryId>;
19
+
20
+ export const PersonalGitHubRepositoryAccess = z.enum(["read", "write"]);
21
+ export type PersonalGitHubRepositoryAccess = z.infer<typeof PersonalGitHubRepositoryAccess>;
22
+
23
+ export const PersonalGitHubRepositoryPermissions = z
24
+ .object({
25
+ pull: z.boolean(),
26
+ push: z.boolean(),
27
+ admin: z.boolean(),
28
+ maintain: z.boolean(),
29
+ triage: z.boolean(),
30
+ })
31
+ .strict();
32
+ export type PersonalGitHubRepositoryPermissions = z.infer<
33
+ typeof PersonalGitHubRepositoryPermissions
34
+ >;
35
+
36
+ export const PersonalGitHubRepositoryVisibility = z.enum(["public", "private", "internal"]);
37
+ export type PersonalGitHubRepositoryVisibility = z.infer<typeof PersonalGitHubRepositoryVisibility>;
38
+
39
+ const PersonalGitHubRepositoryFullName = z
40
+ .string()
41
+ .min(3)
42
+ .max(140)
43
+ .regex(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})\/[A-Za-z0-9_.-]{1,100}$/u);
44
+
45
+ export function canonicalPersonalGitHubRepositoryUrl(fullName: string): string {
46
+ return `https://github.com/${fullName}`;
47
+ }
48
+
49
+ /** A bounded, credential-free projection verified directly against GitHub. */
50
+ export const PersonalGitHubRepository = z
51
+ .object({
52
+ repositoryId: PersonalGitHubRepositoryId,
53
+ fullName: PersonalGitHubRepositoryFullName,
54
+ canonicalUrl: z.string().url().max(512),
55
+ defaultBranch: z.string().min(1).max(255),
56
+ visibility: PersonalGitHubRepositoryVisibility,
57
+ private: z.boolean(),
58
+ archived: z.boolean(),
59
+ disabled: z.boolean(),
60
+ permissions: PersonalGitHubRepositoryPermissions,
61
+ })
62
+ .strict()
63
+ .superRefine((repository, context) => {
64
+ if (repository.canonicalUrl !== canonicalPersonalGitHubRepositoryUrl(repository.fullName)) {
65
+ context.addIssue({
66
+ code: "custom",
67
+ path: ["canonicalUrl"],
68
+ message: "canonicalUrl must be derived from fullName",
69
+ });
70
+ }
71
+ if (repository.private !== (repository.visibility === "private")) {
72
+ context.addIssue({
73
+ code: "custom",
74
+ path: ["private"],
75
+ message: "private must agree with visibility",
76
+ });
77
+ }
78
+ });
79
+ export type PersonalGitHubRepository = z.infer<typeof PersonalGitHubRepository>;
80
+
81
+ export const PersonalGitHubSelectedRepository = PersonalGitHubRepository.safeExtend({
82
+ selectedAccess: PersonalGitHubRepositoryAccess,
83
+ selectionGeneration: z.number().int().positive(),
84
+ selectedAt: z.string().datetime({ offset: true }),
85
+ lastVerifiedAt: z.string().datetime({ offset: true }),
86
+ }).strict();
87
+ export type PersonalGitHubSelectedRepository = z.infer<typeof PersonalGitHubSelectedRepository>;
88
+
89
+ export const PersonalGitHubRepositorySelectionState = z
90
+ .object({
91
+ connectionAuthorityGeneration: z.number().int().positive(),
92
+ credentialBindingId: z.string().uuid(),
93
+ providerPrincipalId: PersonalGitHubRepositoryId,
94
+ selectionGeneration: z.number().int().nonnegative(),
95
+ repositories: z
96
+ .array(PersonalGitHubSelectedRepository)
97
+ .max(PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX),
98
+ })
99
+ .strict();
100
+ export type PersonalGitHubRepositorySelectionState = z.infer<
101
+ typeof PersonalGitHubRepositorySelectionState
102
+ >;
103
+
104
+ export const ListPersonalGitHubRepositoriesQuery = z
105
+ .object({
106
+ cursor: z.coerce.number().int().positive().max(10_000).default(1),
107
+ limit: z.coerce.number().int().min(1).max(PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX).default(50),
108
+ })
109
+ .strict();
110
+ export type ListPersonalGitHubRepositoriesQuery = z.infer<
111
+ typeof ListPersonalGitHubRepositoriesQuery
112
+ >;
113
+
114
+ export const PersonalGitHubRepositoryCatalogItem = PersonalGitHubRepository.safeExtend({
115
+ selectedAccess: PersonalGitHubRepositoryAccess.nullable(),
116
+ }).strict();
117
+ export type PersonalGitHubRepositoryCatalogItem = z.infer<
118
+ typeof PersonalGitHubRepositoryCatalogItem
119
+ >;
120
+
121
+ export const ListPersonalGitHubRepositoriesResponse = z
122
+ .object({
123
+ repositories: z
124
+ .array(PersonalGitHubRepositoryCatalogItem)
125
+ .max(PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX),
126
+ nextCursor: z.number().int().positive().nullable(),
127
+ selection: PersonalGitHubRepositorySelectionState,
128
+ })
129
+ .strict();
130
+ export type ListPersonalGitHubRepositoriesResponse = z.infer<
131
+ typeof ListPersonalGitHubRepositoriesResponse
132
+ >;
133
+
134
+ export const PersonalGitHubRepositorySelectionInput = z
135
+ .object({
136
+ repositoryId: PersonalGitHubRepositoryId,
137
+ fullName: PersonalGitHubRepositoryFullName,
138
+ access: PersonalGitHubRepositoryAccess,
139
+ })
140
+ .strict();
141
+ export type PersonalGitHubRepositorySelectionInput = z.infer<
142
+ typeof PersonalGitHubRepositorySelectionInput
143
+ >;
144
+
145
+ export const ReplacePersonalGitHubRepositorySelectionsRequest = z
146
+ .object({
147
+ expectedConnectionAuthorityGeneration: z.number().int().positive(),
148
+ expectedSelectionGeneration: z.number().int().nonnegative(),
149
+ idempotencyKey: z.string().trim().min(1).max(200),
150
+ repositories: z
151
+ .array(PersonalGitHubRepositorySelectionInput)
152
+ .max(PERSONAL_GITHUB_REPOSITORY_CATALOG_MAX),
153
+ })
154
+ .strict()
155
+ .superRefine((request, context) => {
156
+ const repositoryIds = new Set<string>();
157
+ const fullNames = new Set<string>();
158
+ request.repositories.forEach((repository, index) => {
159
+ const normalizedFullName = repository.fullName.toLowerCase();
160
+ if (repositoryIds.has(repository.repositoryId)) {
161
+ context.addIssue({
162
+ code: "custom",
163
+ path: ["repositories", index, "repositoryId"],
164
+ message: "repositoryId must be unique",
165
+ });
166
+ }
167
+ if (fullNames.has(normalizedFullName)) {
168
+ context.addIssue({
169
+ code: "custom",
170
+ path: ["repositories", index, "fullName"],
171
+ message: "fullName must be unique",
172
+ });
173
+ }
174
+ repositoryIds.add(repository.repositoryId);
175
+ fullNames.add(normalizedFullName);
176
+ });
177
+ });
178
+ export type ReplacePersonalGitHubRepositorySelectionsRequest = z.infer<
179
+ typeof ReplacePersonalGitHubRepositorySelectionsRequest
180
+ >;
181
+
182
+ export const VerifyPersonalGitHubRepositorySelectionsRequest = z
183
+ .object({
184
+ expectedConnectionAuthorityGeneration: z.number().int().positive(),
185
+ expectedSelectionGeneration: z.number().int().nonnegative(),
186
+ idempotencyKey: z.string().trim().min(1).max(200),
187
+ })
188
+ .strict();
189
+ export type VerifyPersonalGitHubRepositorySelectionsRequest = z.infer<
190
+ typeof VerifyPersonalGitHubRepositorySelectionsRequest
191
+ >;
192
+
193
+ /**
194
+ * Owner-visible, credential-free metadata for one dedicated personal GitHub
195
+ * OAuth connection. Repository selections are a separate authority and never
196
+ * live in this credential record.
197
+ */
198
+ export const PersonalGitHubConnectionMetadata = z
199
+ .object({
200
+ credentialRole: z.literal(PERSONAL_GITHUB_CREDENTIAL_ROLE),
201
+ providerFamily: z.literal(PERSONAL_GITHUB_PROVIDER_FAMILY),
202
+ providerPrincipalId: z.string().regex(/^\d+$/u),
203
+ githubUserId: z.string().regex(/^\d+$/u),
204
+ githubLogin: z.string().min(1).max(100),
205
+ oauthEnvironment: z.string().min(1).max(128),
206
+ oauthClientMarker: z.string().regex(/^[a-f0-9]{32}$/u),
207
+ credentialBindingId: z.string().uuid(),
208
+ connectedAt: z.string().datetime({ offset: true }),
209
+ lastVerifiedAt: z.string().datetime({ offset: true }),
210
+ disconnectedAt: z.string().datetime({ offset: true }).nullable().optional(),
211
+ refreshTokenExpiresAt: z.string().datetime({ offset: true }).nullable().optional(),
212
+ })
213
+ .passthrough();
214
+ export type PersonalGitHubConnectionMetadata = z.infer<typeof PersonalGitHubConnectionMetadata>;
215
+
216
+ export const PersonalGitHubOAuthStartRequest = z
217
+ .object({
218
+ /** Existing exact connection generation to re-authorize in place. */
219
+ connectionId: z.string().uuid().optional(),
220
+ /** Same-workspace UI path restored after the callback. */
221
+ returnPath: z.string().min(1).max(2048).optional(),
222
+ })
223
+ .strict();
224
+ export type PersonalGitHubOAuthStartRequest = z.infer<typeof PersonalGitHubOAuthStartRequest>;
225
+
226
+ export const PersonalGitHubOAuthStartResponse = z
227
+ .object({
228
+ authorizationUrl: z.string().url(),
229
+ expiresAt: z.string().datetime({ offset: true }),
230
+ })
231
+ .strict();
232
+ export type PersonalGitHubOAuthStartResponse = z.infer<typeof PersonalGitHubOAuthStartResponse>;
233
+
234
+ export const PersonalGitHubConnectionStatusResponse = z
235
+ .object({
236
+ enabled: z.boolean(),
237
+ connection: ConnectionMetadata.nullable(),
238
+ reviewUrl: z.string().url().nullable(),
239
+ })
240
+ .strict();
241
+ export type PersonalGitHubConnectionStatusResponse = z.infer<
242
+ typeof PersonalGitHubConnectionStatusResponse
243
+ >;
244
+
245
+ export const PersonalGitHubDisconnectRequest = z
246
+ .object({
247
+ expectedVersion: z.number().int().positive(),
248
+ idempotencyKey: z.string().trim().min(1).max(200),
249
+ })
250
+ .strict();
251
+ export type PersonalGitHubDisconnectRequest = z.infer<typeof PersonalGitHubDisconnectRequest>;
252
+
253
+ export function isPersonalGitHubConnection(
254
+ connection: Pick<z.infer<typeof ConnectionMetadata>, "providerDomain" | "kind" | "metadata">,
255
+ ): boolean {
256
+ return (
257
+ connection.providerDomain.toLowerCase() === PERSONAL_GITHUB_PROVIDER_DOMAIN &&
258
+ connection.kind === "oauth2" &&
259
+ PersonalGitHubConnectionMetadata.safeParse(connection.metadata).success
260
+ );
261
+ }
262
+
263
+ export function hasReservedPersonalGitHubMetadata(
264
+ metadata: Record<string, unknown> | undefined,
265
+ ): boolean {
266
+ return metadata?.credentialRole === PERSONAL_GITHUB_CREDENTIAL_ROLE;
267
+ }
@@ -174,6 +174,11 @@ export const PreferenceRegistryEvent = z.object({
174
174
  });
175
175
  export type PreferenceRegistryEvent = z.infer<typeof PreferenceRegistryEvent>;
176
176
 
177
+ export const PreferenceRegistryActivationAuthority = z.enum(["human_confirmed", "automatic"]);
178
+ export type PreferenceRegistryActivationAuthority = z.infer<
179
+ typeof PreferenceRegistryActivationAuthority
180
+ >;
181
+
177
182
  export const PreferenceRegistryDescriptor = z.object({
178
183
  id: z.string().uuid(),
179
184
  stableKey: PreferenceRegistryStableKey,
@@ -185,6 +190,18 @@ export const PreferenceRegistryDescriptor = z.object({
185
190
  contentHash: hash,
186
191
  precedence: PreferenceRegistryPrecedence,
187
192
  provenance: PreferenceRegistryDescriptorProvenance,
193
+ // How the active revision became active, derived from the governed-learning
194
+ // activation receipt rather than stored on the revision. `provenance.trust`
195
+ // stays the frozen creation-time fact - a revision proposed by an agent is
196
+ // `untrusted_proposal` forever, which is correct and immutable - while this
197
+ // says whether a human explicitly confirmed the activation or policy
198
+ // activated it automatically. Null when the revision became active outside
199
+ // governed learning, so no receipt describes it.
200
+ // Defaulted, not merely nullable: snapshots written before this field
201
+ // existed are immutable and their stored JSON simply has no answer. Parsing
202
+ // those as null is the truthful reading, and it keeps their pinned
203
+ // descriptor hash valid because the stored text is untouched.
204
+ activationAuthority: PreferenceRegistryActivationAuthority.nullable().default(null),
188
205
  expiresAt: z.string().datetime().nullable(),
189
206
  retrievalHandle: z.string().min(1).max(512),
190
207
  });
@@ -0,0 +1,242 @@
1
+ import { z } from "zod";
2
+ import {
3
+ AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_MAX_CHARS,
4
+ AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_TOO_LONG_MESSAGE,
5
+ AGENT_AUTHORED_PREFERENCE_CONTENT_MAX_CHARS,
6
+ AGENT_AUTHORED_PREFERENCE_CONTENT_TOO_LONG_MESSAGE,
7
+ } from "./agent-authored-durable-text";
8
+ import {
9
+ CompanyBrainLearningDecisionSummary,
10
+ CompanyBrainLearningStepFailure,
11
+ } from "./company-brain-governed-writes";
12
+ import { GovernedLearningActivationDestination } from "./governed-learning-activation";
13
+ import { HumanInputQuestion } from "./index";
14
+ import {
15
+ PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS,
16
+ PREFERENCE_REGISTRY_TITLE_MAX_CHARS,
17
+ PreferenceRegistryStableKey,
18
+ } from "./preference-registry";
19
+ import { WorkspaceInstructionPolicyTarget } from "./workspace-instruction-policies";
20
+
21
+ /**
22
+ * Explicit user-directed durable write ("remember X for this workspace").
23
+ *
24
+ * The lane is the Company Brain area the content belongs to:
25
+ * - `preference`: a Ways-of-working preference (how agents should act);
26
+ * - `instruction_policy`: a mandatory workspace rule ("always"/"never");
27
+ * - `knowledge`: a company/product/people fact.
28
+ *
29
+ * v1 supports the workspace scope only. Personal and organization scopes are
30
+ * separate authorities that are not yet active for governed writes.
31
+ */
32
+ export const RememberLane = z.enum(["preference", "instruction_policy", "knowledge"]);
33
+ export type RememberLane = z.infer<typeof RememberLane>;
34
+
35
+ export const RememberScope = z.enum(["workspace"]);
36
+ export type RememberScope = z.infer<typeof RememberScope>;
37
+
38
+ /**
39
+ * Ceiling for the Knowledge lane, which is retrieval evidence rather than
40
+ * always-composed prompt text. The prompt-composed lanes are bounded far more
41
+ * tightly: see `AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_MAX_CHARS` and
42
+ * `AGENT_AUTHORED_PREFERENCE_CONTENT_MAX_CHARS`.
43
+ */
44
+ export const REMEMBER_CONTENT_MAX_CHARS = 4_000;
45
+
46
+ const rememberBase = {
47
+ operationId: z.string().uuid(),
48
+ scope: RememberScope.default("workspace"),
49
+ /** The exact user-directed content to remember, in the user's words. */
50
+ content: z.string().trim().min(1).max(REMEMBER_CONTENT_MAX_CHARS),
51
+ /** Why the agent believes the user asked for this to be remembered. */
52
+ reason: z.string().trim().min(1).max(4_096),
53
+ };
54
+
55
+ export const RememberRequest = z.discriminatedUnion("lane", [
56
+ z
57
+ .object({
58
+ ...rememberBase,
59
+ lane: z.literal("preference"),
60
+ // Only the short title/description descriptors are prompt-composed; the
61
+ // content is retrieved on demand, so this length is retrieval cost rather
62
+ // than standing prompt cost, and gets more room than a rule rather than
63
+ // less.
64
+ content: z
65
+ .string()
66
+ .trim()
67
+ .min(1)
68
+ .max(
69
+ AGENT_AUTHORED_PREFERENCE_CONTENT_MAX_CHARS,
70
+ AGENT_AUTHORED_PREFERENCE_CONTENT_TOO_LONG_MESSAGE,
71
+ ),
72
+ stableKey: PreferenceRegistryStableKey,
73
+ title: z.string().trim().min(1).max(PREFERENCE_REGISTRY_TITLE_MAX_CHARS),
74
+ description: z
75
+ .string()
76
+ .trim()
77
+ .min(1)
78
+ .max(PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS),
79
+ })
80
+ .strict(),
81
+ z
82
+ .object({
83
+ ...rememberBase,
84
+ lane: z.literal("instruction_policy"),
85
+ // A mandatory rule is composed verbatim into the prompt of every session
86
+ // it applies to, for as long as it stays active, so this is the tightest
87
+ // agent budget in the Company Brain.
88
+ content: z
89
+ .string()
90
+ .trim()
91
+ .min(1)
92
+ .max(
93
+ AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_MAX_CHARS,
94
+ AGENT_AUTHORED_INSTRUCTION_POLICY_CONTENT_TOO_LONG_MESSAGE,
95
+ ),
96
+ target: WorkspaceInstructionPolicyTarget.default({
97
+ kind: "policy",
98
+ scope: "global",
99
+ roleKey: null,
100
+ }),
101
+ })
102
+ .strict(),
103
+ z
104
+ .object({
105
+ ...rememberBase,
106
+ lane: z.literal("knowledge"),
107
+ /** Short entity label the fact is about (company, product, person, team, ...). */
108
+ subject: z.string().trim().min(1).max(512),
109
+ })
110
+ .strict(),
111
+ ]);
112
+ export type RememberRequest = z.infer<typeof RememberRequest>;
113
+
114
+ /**
115
+ * Bound structured human-input question that authorizes a confirmed remember.
116
+ * The question id binds the exact confirmation target: the
117
+ * `knowledge_change_proposals` id for Ways-of-working lanes, or the
118
+ * `knowledge_claims` id for the Knowledge lane.
119
+ */
120
+ export const REMEMBER_HUMAN_INPUT_SAVE_OPTION = "save" as const;
121
+ export const REMEMBER_HUMAN_INPUT_SKIP_OPTION = "skip" as const;
122
+ export function rememberHumanInputQuestionId(targetId: string): string {
123
+ return `remember:${targetId}`;
124
+ }
125
+
126
+ // z.lazy: this module is re-exported from ./index, so resolve the question
127
+ // schema at parse time instead of at import time.
128
+ export const RememberHumanInputPrompt = z.object({
129
+ questions: z.array(z.lazy(() => HumanInputQuestion)).length(1),
130
+ allowSkip: z.literal(false),
131
+ });
132
+ export type RememberHumanInputPrompt = z.infer<typeof RememberHumanInputPrompt>;
133
+
134
+ export const RememberActivationSummary = z.discriminatedUnion("destination", [
135
+ z.object({
136
+ destination: GovernedLearningActivationDestination,
137
+ receiptId: z.string().uuid(),
138
+ destinationRevisionId: z.string().uuid().nullable(),
139
+ effectiveAt: z.string().datetime().nullable(),
140
+ authorityKind: z.enum(["automatic", "human_confirmed"]),
141
+ /** The `/learning` API/SDK history exposes exact undo for this receipt. */
142
+ undo: z.literal("learning_history"),
143
+ }),
144
+ z.object({
145
+ destination: z.literal("knowledge"),
146
+ receiptId: z.string().uuid(),
147
+ claimId: z.string().uuid(),
148
+ approvalReviewId: z.string().uuid(),
149
+ effectiveAt: z.string().datetime().nullable(),
150
+ authorityKind: z.literal("human_confirmed"),
151
+ /** Knowledge approvals are undone through the Knowledge review lifecycle (`knowledge_correct` or a human revocation). */
152
+ undo: z.literal("knowledge_review"),
153
+ }),
154
+ ]);
155
+ export type RememberActivationSummary = z.infer<typeof RememberActivationSummary>;
156
+
157
+ export const RememberReceipt = z.discriminatedUnion("status", [
158
+ /** Learning policy is off for this source: nothing durable was written. */
159
+ z.object({
160
+ status: z.literal("blocked"),
161
+ operationId: z.string().uuid(),
162
+ lane: RememberLane,
163
+ scope: RememberScope,
164
+ reason: z.literal("learning_policy_off"),
165
+ }),
166
+ /** Kept for callers that still expect review-only Knowledge; not returned by `remember` today. */
167
+ z.object({
168
+ status: z.literal("proposed_for_review"),
169
+ operationId: z.string().uuid(),
170
+ lane: RememberLane,
171
+ scope: RememberScope,
172
+ noteId: z.string().uuid(),
173
+ claimId: z.string().uuid(),
174
+ evidenceId: z.string().uuid(),
175
+ reviewId: z.string().uuid().nullable(),
176
+ }),
177
+ /** Activated immediately (automatic policy) through the destination lifecycle. */
178
+ z.object({
179
+ status: z.literal("activated"),
180
+ operationId: z.string().uuid(),
181
+ lane: RememberLane,
182
+ scope: RememberScope,
183
+ noteId: z.string().uuid(),
184
+ proposalId: z.string().uuid(),
185
+ learning: CompanyBrainLearningDecisionSummary.nullable(),
186
+ activation: RememberActivationSummary,
187
+ }),
188
+ /**
189
+ * The proposal is durable but the workspace policy will not activate it on
190
+ * its own. The agent must ask the human exactly this question through the
191
+ * built-in `request_human_input` tool, then call `remember_confirm` with the
192
+ * returned request id.
193
+ */
194
+ z.object({
195
+ status: z.literal("confirmation_required"),
196
+ operationId: z.string().uuid(),
197
+ lane: RememberLane,
198
+ scope: RememberScope,
199
+ noteId: z.string().uuid(),
200
+ /** Ways-of-working lanes confirm a change proposal; Knowledge confirms the claim. */
201
+ proposalId: z.string().uuid().nullable(),
202
+ claimId: z.string().uuid(),
203
+ learning: CompanyBrainLearningDecisionSummary.nullable(),
204
+ learningFailure: CompanyBrainLearningStepFailure.nullable(),
205
+ humanInput: RememberHumanInputPrompt,
206
+ confirmWith: z.literal("remember_confirm"),
207
+ }),
208
+ ]);
209
+ export type RememberReceipt = z.infer<typeof RememberReceipt>;
210
+
211
+ export const RememberConfirmRequest = z.discriminatedUnion("target", [
212
+ z
213
+ .object({
214
+ target: z.literal("proposal"),
215
+ operationId: z.string().uuid(),
216
+ proposalId: z.string().uuid(),
217
+ /** `learning.receiptId` from the `confirmation_required` remember receipt. */
218
+ decisionReceiptId: z.string().uuid(),
219
+ /** The `requestId` returned by `request_human_input`. */
220
+ humanInputRequestId: z.string().uuid(),
221
+ })
222
+ .strict(),
223
+ z
224
+ .object({
225
+ target: z.literal("knowledge_claim"),
226
+ operationId: z.string().uuid(),
227
+ claimId: z.string().uuid(),
228
+ humanInputRequestId: z.string().uuid(),
229
+ })
230
+ .strict(),
231
+ ]);
232
+ export type RememberConfirmRequest = z.infer<typeof RememberConfirmRequest>;
233
+
234
+ export const RememberConfirmReceipt = z.object({
235
+ status: z.literal("activated"),
236
+ operationId: z.string().uuid(),
237
+ proposalId: z.string().uuid().nullable(),
238
+ claimId: z.string().uuid(),
239
+ decisionReceiptId: z.string().uuid().nullable(),
240
+ activation: RememberActivationSummary,
241
+ });
242
+ export type RememberConfirmReceipt = z.infer<typeof RememberConfirmReceipt>;
@@ -0,0 +1,65 @@
1
+ import { z } from "zod";
2
+
3
+ import { RetainedArtifactReferenceSchema } from "./retained-output";
4
+
5
+ /**
6
+ * Channel-A currently returns one bounded binary-safe read. Keep publication
7
+ * below that ceiling so an extra sentinel byte can distinguish an exact file
8
+ * from a truncated prefix.
9
+ */
10
+ export const SANDBOX_FILE_ARTIFACT_MAX_BYTES = 25 * 1024 * 1024 - 1;
11
+
12
+ export const PublishSandboxFileArtifactRequest = z
13
+ .object({
14
+ path: z.string().min(1).max(4_096),
15
+ })
16
+ .strict();
17
+ export type PublishSandboxFileArtifactRequest = z.infer<typeof PublishSandboxFileArtifactRequest>;
18
+
19
+ /**
20
+ * Closed model/UI receipt for one exact sandbox-file publication. Storage
21
+ * locators and signed URLs never cross this boundary.
22
+ */
23
+ export const SandboxFileArtifactReceipt = z
24
+ .object({
25
+ type: z.literal("sandbox_file"),
26
+ sandboxPath: z.string().min(1).max(4_096),
27
+ filename: z.string().min(1).max(1_024),
28
+ artifact: RetainedArtifactReferenceSchema,
29
+ })
30
+ .strict()
31
+ .superRefine((value, context) => {
32
+ const pathSegments = value.sandboxPath.split("/");
33
+ if (
34
+ !value.sandboxPath.startsWith("/workspace/") ||
35
+ value.sandboxPath.includes("\0") ||
36
+ pathSegments.some(
37
+ (segment, index) => index > 1 && (!segment || segment === "." || segment === ".."),
38
+ ) ||
39
+ pathSegments.at(-1) !== value.filename
40
+ ) {
41
+ context.addIssue({
42
+ code: "custom",
43
+ path: ["sandboxPath"],
44
+ message: "sandbox path must canonically identify the published filename in /workspace",
45
+ });
46
+ }
47
+ if (value.artifact.kind !== "file" || value.artifact.retention.policy !== "workspace_file") {
48
+ context.addIssue({
49
+ code: "custom",
50
+ path: ["artifact"],
51
+ message: "sandbox files require a permanent workspace-file artifact",
52
+ });
53
+ }
54
+ if (
55
+ value.artifact.originalBytes < 1 ||
56
+ value.artifact.originalBytes > SANDBOX_FILE_ARTIFACT_MAX_BYTES
57
+ ) {
58
+ context.addIssue({
59
+ code: "custom",
60
+ path: ["artifact", "originalBytes"],
61
+ message: "sandbox file size is outside the publication byte limit",
62
+ });
63
+ }
64
+ });
65
+ export type SandboxFileArtifactReceipt = z.infer<typeof SandboxFileArtifactReceipt>;
@@ -52,6 +52,84 @@ export type NativeSnapshotDescriptor = {
52
52
 
53
53
  export type WorkspaceArchiveDescriptor = TarWorkspaceArchiveDescriptor | NativeSnapshotDescriptor;
54
54
 
55
+ export const WORKSPACE_ARCHIVE_OBJECT_REF_SCHEMA = "sandbox_archive_object_v1" as const;
56
+
57
+ /** Compact object-storage locator for portable tar bytes. The SHA-256/size in
58
+ * `workspaceArchiveMeta` remain the verification authority. */
59
+ export type WorkspaceArchiveObjectRef = {
60
+ schema: typeof WORKSPACE_ARCHIVE_OBJECT_REF_SCHEMA;
61
+ key: string;
62
+ sha256: string;
63
+ bytes: number;
64
+ backend: string;
65
+ };
66
+
67
+ const OBJECT_KEY =
68
+ /^sandbox-archives\/v1\/[0-9a-f-]{36}\/[0-9a-f-]{36}\/[0-9a-f-]{36}\/wa1:[0-9]{13}:[0-9a-f]{64}\.tar$/i;
69
+
70
+ export function parseWorkspaceArchiveObjectRef(value: unknown): WorkspaceArchiveObjectRef | null {
71
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
72
+ const candidate = value as Partial<WorkspaceArchiveObjectRef>;
73
+ if (
74
+ candidate.schema !== WORKSPACE_ARCHIVE_OBJECT_REF_SCHEMA ||
75
+ typeof candidate.key !== "string" ||
76
+ !OBJECT_KEY.test(candidate.key) ||
77
+ typeof candidate.sha256 !== "string" ||
78
+ !SHA256.test(candidate.sha256) ||
79
+ !nonnegativeInteger(candidate.bytes) ||
80
+ candidate.bytes <= 0 ||
81
+ typeof candidate.backend !== "string" ||
82
+ candidate.backend.length === 0 ||
83
+ candidate.backend.length > 64
84
+ ) {
85
+ return null;
86
+ }
87
+ return {
88
+ schema: WORKSPACE_ARCHIVE_OBJECT_REF_SCHEMA,
89
+ key: candidate.key,
90
+ sha256: candidate.sha256,
91
+ bytes: candidate.bytes,
92
+ backend: candidate.backend,
93
+ };
94
+ }
95
+
96
+ export function workspaceArchiveObjectKey(input: {
97
+ accountId: string;
98
+ workspaceId: string;
99
+ sandboxGroupId: string;
100
+ revision: string;
101
+ }): string {
102
+ return `sandbox-archives/v1/${input.accountId}/${input.workspaceId}/${input.sandboxGroupId}/${input.revision}.tar`;
103
+ }
104
+
105
+ export function workspaceArchivePayloadPresent(
106
+ sessionState: Record<string, unknown> | null | undefined,
107
+ ): boolean {
108
+ if (!sessionState) return false;
109
+ if (
110
+ typeof sessionState.workspaceArchive === "string" &&
111
+ sessionState.workspaceArchive.length > 0
112
+ ) {
113
+ return true;
114
+ }
115
+ return parseWorkspaceArchiveObjectRef(sessionState.workspaceArchiveRef) !== null;
116
+ }
117
+
118
+ /** Restore may inline object bytes in memory for hydrate. That copy must never
119
+ * be published onto a lease when a durable object-storage ref exists. */
120
+ export function omitInlineWorkspaceArchiveWhenObjectRefPresent(
121
+ sessionState: Record<string, unknown>,
122
+ ): Record<string, unknown> {
123
+ const next = { ...sessionState };
124
+ if (parseWorkspaceArchiveObjectRef(next.workspaceArchiveRef)) {
125
+ delete next.workspaceArchive;
126
+ }
127
+ if (parseWorkspaceArchiveObjectRef(next.workspaceArchivePrevRef)) {
128
+ delete next.workspaceArchivePrev;
129
+ }
130
+ return next;
131
+ }
132
+
55
133
  export const NATIVE_SNAPSHOT_PREFIXES: ReadonlyArray<{
56
134
  provider: NativeSnapshotProvider;
57
135
  prefix: string;