@recursiv/sdk 0.7.83 → 0.7.93

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 (40) hide show
  1. package/README.md +86 -2
  2. package/dist/assistant/index.d.ts +11 -3
  3. package/dist/assistant/index.js +11 -3
  4. package/dist/assistant/render.d.ts +25 -2
  5. package/dist/assistant/render.js +197 -16
  6. package/dist/assistant/subjectBundle.js +20 -3
  7. package/dist/assistant/turnCaps.d.ts +3 -0
  8. package/dist/assistant/turnCaps.js +141 -0
  9. package/dist/assistant/types.d.ts +223 -7
  10. package/dist/assistant/types.js +15 -0
  11. package/dist/index.d.ts +12 -6
  12. package/dist/index.js +8 -2
  13. package/dist/privacy/facts.generated.d.ts +79 -0
  14. package/dist/privacy/facts.generated.js +93 -0
  15. package/dist/privacy/index.d.ts +48 -0
  16. package/dist/privacy/index.js +42 -0
  17. package/dist/resources/discovery-merge.d.ts +17 -1
  18. package/dist/resources/discovery-merge.js +84 -4
  19. package/dist/resources/discovery-progressive.d.ts +4 -3
  20. package/dist/resources/discovery-progressive.js +11 -8
  21. package/dist/resources/discovery.d.ts +9 -1
  22. package/dist/resources/discovery.js +62 -15
  23. package/dist/resources/feeds.d.ts +15 -6
  24. package/dist/resources/feeds.js +2 -1
  25. package/dist/resources/integrations.d.ts +3 -0
  26. package/dist/resources/privacy.d.ts +13 -0
  27. package/dist/resources/privacy.js +14 -0
  28. package/dist/resources/protocols.d.ts +99 -11
  29. package/dist/resources/protocols.js +45 -0
  30. package/dist/resources/sealed.d.ts +127 -7
  31. package/dist/resources/sealed.js +33 -6
  32. package/dist/resources/settings.d.ts +3 -1
  33. package/dist/resources/settings.js +3 -1
  34. package/dist/resources/signals.d.ts +129 -6
  35. package/dist/resources/signals.js +58 -2
  36. package/dist/social-protocol-ids.d.ts +28 -0
  37. package/dist/social-protocol-ids.js +30 -0
  38. package/dist/types.d.ts +45 -0
  39. package/llm.md +17 -6
  40. package/package.json +6 -1
@@ -0,0 +1,141 @@
1
+ /**
2
+ * `sealedTurnCaps`: what one Sealed message may carry (sealed-full-scope-v1 3.2 rule 5, 4.2, 4.3 and 2.6). A message is
3
+ * dangerous when it holds three things at once: something about the member, words or pictures from someone else, and
4
+ * a way to send data out. Web search is a way out (page opens and search words both reach Exa), and nothing screens a
5
+ * post before the model reads it. So:
6
+ *
7
+ * - a message that searches never carries memory, About you or a picture from the phone. Those are never dropped to
8
+ * make room for search: search is what turns off ('search.off_mix');
9
+ * - a message with someone else's public post in it, or earlier in its chat, doesn't search until Tinfoil limits page
10
+ * opens (ask 3, `page_opens_limited`, default false) ('search.off_subject');
11
+ * - members-only posts and picked chat messages never search ('search.off_members'), nor do encrypted-chat messages
12
+ * ('search.e2ee'): their words would reach a search company without their authors agreeing;
13
+ * - a message that searches carries only the question (and, after ask 3, the public post it asks about), never the
14
+ * chat's earlier messages or George's earlier answers, before and after ask 3 (S-D9) ('search.question_only');
15
+ * - a Both message never searches ('both.no_search') and never carries a picture from the phone ('both.no_photo'),
16
+ * because its Standard half is an ordinary Minds turn. For the same reason a Both message with encrypted-chat
17
+ * messages throws: an encrypted-chat ask is Sealed only (G21), and Both would send the messages to Standard;
18
+ * - the saved facts go only when Sealed memory is on and on for this chat: the header chip in the member's own chat,
19
+ * and only the member's "Use what George remembers" tick in an ask or chat carrying someone else's content (George
20
+ * plan 4.7; the chip alone never counts there); never in a temporary chat or with encrypted-chat messages. About
21
+ * you, when "Use these" is on, follows the same rules except that it doesn't need memory on;
22
+ * - an encrypted-chat ask carries no picture from the phone (G21: one message of words);
23
+ * - temporary chats neither read nor write memory, and a suggestion in an answer to a message that may hold anyone
24
+ * else's words (a post, chat messages, search results, a picture from the phone, which may be a screenshot, or
25
+ * earlier answers in a chat that searched or carried a phone picture) is never offered for saving (4.2).
26
+ *
27
+ * What the caps cannot see for themselves (someone else's content, how many pictures from the phone this message
28
+ * carries, a temporary chat, an earlier search, an earlier phone picture, earlier messages in the chat) are required
29
+ * inputs: one left out throws rather than reading as "none", so a caller that forgot one never sends more than it
30
+ * should or loses a line the member is owed. More than 3 pictures from the phone throws too: a message carries at most
31
+ * 3 pictures in all (2.2), and the composer caps them.
32
+ *
33
+ * Pure: no clock, randomness or network. The same input gives the same caps on every phone and server.
34
+ */
35
+ import { BUNDLE_PICTURE_LIMITS } from './render.js';
36
+ import { SEALED_CONTENT_KINDS } from './types.js';
37
+ /** A choice that sends something counts only when it is exactly true. */
38
+ const isOn = (value) => value === true;
39
+ /** A restriction counts for anything but false, null or absent, so a value it cannot read restricts. */
40
+ const isSet = (value) => value !== undefined && value !== null && value !== false;
41
+ const KINDS = new Set(SEALED_CONTENT_KINDS);
42
+ /** A required restriction: absent or null throws, so a caller that forgot it never reads as unrestricted. */
43
+ function restriction(value, name, pass) {
44
+ if (value === undefined || value === null)
45
+ throw new TypeError(`sealedTurnCaps: ${name} is required (pass ${pass} for none)`);
46
+ return isSet(value);
47
+ }
48
+ function contentKinds(value) {
49
+ const out = new Set();
50
+ if (value === undefined || value === null) {
51
+ throw new TypeError("sealedTurnCaps: others_content is required (pass [] for the member's own words only)");
52
+ }
53
+ if (!Array.isArray(value))
54
+ throw new TypeError('sealedTurnCaps: others_content must be a list of content kinds');
55
+ for (const kind of value) {
56
+ if (!KINDS.has(kind))
57
+ throw new TypeError(`sealedTurnCaps: unknown content kind ${JSON.stringify(kind) ?? String(kind)}`);
58
+ out.add(kind);
59
+ }
60
+ return out;
61
+ }
62
+ /** At most 3 pictures in one message, from the phone and from posts together (sealed-full-scope-v1 2.2). */
63
+ const MAX_PICTURES = BUNDLE_PICTURE_LIMITS.max_pictures;
64
+ function pictureCount(value) {
65
+ // Required: left out, a message with a picture would search beside it, or drop it with no 'search.off_mix' line, and
66
+ // could offer a suggestion from a screenshot.
67
+ if (value === undefined || value === null)
68
+ throw new TypeError('sealedTurnCaps: phone_pictures is required (pass 0 for none)');
69
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0 || value > MAX_PICTURES) {
70
+ throw new TypeError(`sealedTurnCaps: phone_pictures must be a whole number from 0 to ${MAX_PICTURES}: the composer caps them`);
71
+ }
72
+ return value;
73
+ }
74
+ /** What `input`, one Sealed message, may carry. See the module comment for the rules. */
75
+ export function sealedTurnCaps(input) {
76
+ if (!input || typeof input !== 'object')
77
+ throw new TypeError('sealedTurnCaps needs an input object');
78
+ if (input.mode !== 'sealed' && input.mode !== 'both') {
79
+ throw new TypeError("sealedTurnCaps: mode must be 'sealed' or 'both'");
80
+ }
81
+ const both = input.mode === 'both';
82
+ const kinds = contentKinds(input.others_content);
83
+ const others = kinds.size > 0;
84
+ const encrypted = kinds.has('encrypted_chat');
85
+ // G21: an encrypted-chat ask is Sealed only. A Both message's Standard half is an ordinary Minds turn (2.6), so it
86
+ // would put the decrypted messages on Minds and the AI company. No surface offers this, so it is a caller's mistake.
87
+ if (both && encrypted) {
88
+ throw new TypeError("sealedTurnCaps: an encrypted-chat ask is Sealed only (G21): mode 'both' would send it to Standard");
89
+ }
90
+ const membersOnly = kinds.has('members_only_post') || kinds.has('chat_messages');
91
+ const temporary = restriction(input.temporary, 'temporary', 'false');
92
+ const searchedEarlier = restriction(input.searched_earlier, 'searched_earlier', 'false');
93
+ // Decides the 'search.question_only' line (S-D9: the member is told the chat so far was left out), so it is required
94
+ // like the restrictions: left out, a searching message would drop the chat so far without saying so.
95
+ const earlierMessages = restriction(input.earlier_messages, 'earlier_messages', 'false');
96
+ const picturesEarlier = restriction(input.phone_pictures_earlier, 'phone_pictures_earlier', 'false');
97
+ const pictures = pictureCount(input.phone_pictures);
98
+ // The memory message (4.3): never in a temporary chat or with encrypted-chat messages. In the member's own chat the
99
+ // chip turns it on; with someone else's content only the "Use what George remembers" tick does, never the chip.
100
+ const inChat = others ? isOn(input.memory_tick) : isOn(input.memory_in_chat);
101
+ const memory = isOn(input.memory) && inChat && !temporary && !encrypted;
102
+ const aboutYou = isOn(input.about_you) && !temporary && !encrypted && (!others || isOn(input.memory_tick));
103
+ // G21: an encrypted-chat ask is one message of words.
104
+ const phonePictures = pictures > 0 && !both && !encrypted;
105
+ let search = false;
106
+ let searchOff = null;
107
+ if (isOn(input.search)) {
108
+ if (both)
109
+ searchOff = 'both.no_search';
110
+ else if (encrypted)
111
+ searchOff = 'search.e2ee';
112
+ else if (membersOnly)
113
+ searchOff = 'search.off_members';
114
+ else if (others && !isOn(input.page_opens_limited))
115
+ searchOff = 'search.off_subject';
116
+ // Memory, About you and pictures stay; search is what turns off.
117
+ else if (memory || aboutYou || phonePictures)
118
+ searchOff = 'search.off_mix';
119
+ else
120
+ search = true;
121
+ }
122
+ const reasons = [];
123
+ if (searchOff)
124
+ reasons.push(searchOff);
125
+ if (search && earlierMessages)
126
+ reasons.push('search.question_only');
127
+ if (pictures > 0 && both)
128
+ reasons.push('both.no_photo');
129
+ return {
130
+ search,
131
+ history: !search,
132
+ memory,
133
+ about_you: aboutYou,
134
+ phone_pictures: phonePictures,
135
+ // Search results are someone else's words too, and so is an earlier answer built from them, which this message
136
+ // carries in its history: a page could plant a "fact" (4.2, gate M3). A picture from the phone may be a screenshot
137
+ // or a meme with someone else's words in it, and an earlier answer about one stays in the history (2.2).
138
+ suggest_memory: memory && !others && !search && !searchedEarlier && !phonePictures && !picturesEarlier,
139
+ reasons,
140
+ };
141
+ }
@@ -31,18 +31,36 @@ export interface SubjectAuthorInput {
31
31
  known_minor?: boolean | null;
32
32
  }
33
33
  /**
34
- * One picture, clip or sound on a post. Only its type and alt text are read: an address or the bytes, if the caller's
35
- * object carries them, are never copied into the bundle.
34
+ * One picture, clip or sound on a post. Only its type, its alt text, `held`, and for pictures its plain id and
35
+ * `checked_at` are read: an address or the bytes, if the caller's object carries them, are never copied into the bundle.
36
36
  */
37
37
  export interface SubjectMediaInput {
38
38
  type?: string | null;
39
39
  /** What the author wrote for it. */
40
40
  alt_text?: string | null;
41
41
  /**
42
- * Under a child-safety hold or reported: its alt text and the post's stored caption are left out. Server-side input,
43
- * like the post's hold. Any value but `false`, `null` or absent counts as set.
42
+ * Under a child-safety hold or reported: the builder leaves out its alt text, and the post's stored caption, which may
43
+ * describe it. Any value but `false`, `null` or absent counts as set. `true` is server-side, like the post's hold:
44
+ * never send it to another member's client. A server leaves held media out of that payload, and leaves out the
45
+ * post's stored caption (`ai_caption`) whenever any of its media is held: a client builder cannot see media it was
46
+ * never sent, so it keeps whatever caption the payload carries. `false` is also the payload's "not held" mark
47
+ * (sealed-full-scope-v1 2.1): a picture goes to a model as a picture only when `held` is exactly `false`, so pass
48
+ * it through from the payload. Absent or null still goes as alt text, but never as a picture.
44
49
  */
45
50
  held?: boolean | null;
51
+ /**
52
+ * The media's id in the post payload (`media[].id`), so a caller that renders with pictures can find the picture in
53
+ * its own image cache. Kept for pictures only, and only when it is a plain id: never an address.
54
+ */
55
+ id?: string | null;
56
+ /**
57
+ * When Minds last matched this picture against the child-safety hash lists (the post payload's `media[].checked_at`,
58
+ * sealed-full-scope-v1 2.1, gate P1): an ISO time with its zone, written only by the server. Kept only when `held`
59
+ * is exactly `false`. A picture can go to a model as a picture only while this is under 24 hours old by the
60
+ * renderer's clock; absent, not an ISO time with its zone, or without `held: false`, means alt text and the stored
61
+ * caption only, as for every other picture.
62
+ */
63
+ checked_at?: string | null;
46
64
  }
47
65
  export interface SubjectLinkCardInput {
48
66
  url?: string | null;
@@ -150,6 +168,13 @@ export type BundleItemRole = 'subject' | 'parent' | 'quoted' | 'reply';
150
168
  export interface BundleMedia {
151
169
  type: 'image' | 'video' | 'audio' | 'other';
152
170
  alt_text: string | null;
171
+ /** Pictures only: the media's id, when the input had a plain one. Never written into model input. */
172
+ id?: string;
173
+ /**
174
+ * Pictures only: Minds' last child-safety check of it (ISO time, UTC), when the input had a valid one and marked the
175
+ * picture not held (`held: false`).
176
+ */
177
+ checked_at?: string;
153
178
  }
154
179
  export interface BundleCounts {
155
180
  votes?: number;
@@ -259,7 +284,64 @@ export interface RenderBundleOptions {
259
284
  boundary: string;
260
285
  /** For 'translate': the language to translate into, as a BCP 47 tag ('es', 'pt-BR'). */
261
286
  language?: string | null;
287
+ /**
288
+ * Attach post pictures as pictures (sealed-full-scope-v1 2.1 and 2.2). Without it, or when no picture qualifies,
289
+ * every picture goes as its alt text and the stored caption only, and the output is exactly as before.
290
+ */
291
+ pictures?: RenderPictureOptions | null;
262
292
  }
293
+ /** A post picture in a bundle that may go to the model as a picture: see `bundlePictures`. */
294
+ export interface BundlePicture {
295
+ /** The id of the item the picture is on. */
296
+ item_id: string;
297
+ /** Where that item sits: the asked-about post, its parent or its quote. A reply's pictures never go as pictures. */
298
+ role: Exclude<BundleItemRole, 'reply'>;
299
+ /** The picture's id in the post payload: find its bytes in your image cache by this. */
300
+ media_id: string;
301
+ /** Which picture of its item it is, from 1, as the content numbers them ("picture 2 alt text"). */
302
+ number: number;
303
+ /** Minds' last child-safety check of it (ISO time, UTC), from the bundle, for your own freshness check. */
304
+ checked_at: string;
305
+ }
306
+ export interface BundlePictureOptions {
307
+ /** Your clock, in milliseconds since 1970 UTC, or a Date. The renderer reads no clock of its own. */
308
+ now: number | Date;
309
+ /**
310
+ * How many post pictures this message still has room for: 3 (the per-message limit, sealed-full-scope-v1 2.2) minus
311
+ * the pictures from the phone it carries (`Math.max(0, 3 - phonePictures)`). A whole number; above 3 counts as 3;
312
+ * absent means 3; below 0 throws. Pass the same value to bundlePictures and renderBundleForModel.
313
+ */
314
+ max?: number | null;
315
+ }
316
+ export interface RenderPictureOptions extends BundlePictureOptions {
317
+ /**
318
+ * The pictures you approved: the list bundlePictures gave you, less any your own checks left out. The renderer
319
+ * attaches only a picture on this list that still qualifies at `now`, so a picture left out here, or one that went
320
+ * stale since, goes as alt text only, and no other picture takes its place. Read `now` again for this call
321
+ * (`Date.now()` after your checks): a later clock can only take pictures away.
322
+ */
323
+ allowed: readonly BundlePicture[];
324
+ /**
325
+ * The picture's bytes from your own image cache: the base64 of a JPEG already prepared on this device (shrunk,
326
+ * re-encoded, metadata stripped; sealed-full-scope-v1 2.2), or null when it has not loaded. Never fetch here: a
327
+ * picture that has not loaded is not sent. Anything but base64 JPEG bytes, or a throw, means that picture goes as alt
328
+ * text only. Asked only for pictures on `allowed`. Prepare first, then check: return exactly the prepared bytes your
329
+ * checks passed for this picture, never a second read of the cache (an entry replaced in between would send a picture
330
+ * nobody checked, and the raw cached file still carries its metadata). The renderer can tell only that the bytes look
331
+ * like a JPEG, not that they were prepared.
332
+ */
333
+ cached: (picture: BundlePicture) => string | null | undefined;
334
+ }
335
+ /** One part of the user message, in the chat-completions content-part shape. */
336
+ export type RenderedUserPart = {
337
+ type: 'text';
338
+ text: string;
339
+ } | {
340
+ type: 'image_url';
341
+ image_url: {
342
+ url: string;
343
+ };
344
+ };
263
345
  /**
264
346
  * A rendered bundle. Render only a bundle this process built from its own reads: the renderer re-checks every field
265
347
  * it writes outside a member line and throws on one that does not fit, but a bundle a client sent has skipped every
@@ -268,15 +350,30 @@ export interface RenderBundleOptions {
268
350
  export interface RenderedBundle {
269
351
  /** Fixed instructions written by the renderer: trusted, for the system role. */
270
352
  system: string;
271
- /** The delimited content, then the task again: for the user role. */
353
+ /**
354
+ * The delimited content, then the task again: for the user role. Words only: when `pictures` is not empty it still
355
+ * says which pictures are attached but cannot carry them, so send `user_parts` instead.
356
+ */
272
357
  user: string;
273
- /** `system` and `user` as one message, for a path that sends one. */
358
+ /**
359
+ * `system` and `user` as one message, for a path that sends one. Only when `pictures` is empty: it names the
360
+ * attached pictures but cannot carry them.
361
+ */
274
362
  text: string;
275
363
  /**
276
364
  * What the rendered content holds: an answer may cite or link these and nothing else, and only as plain links (see
277
- * BundleReferences): never render an image the model wrote.
365
+ * BundleReferences): never render an image the model wrote. Never a picture's address or bytes, attached or not.
278
366
  */
279
367
  references: BundleReferences;
368
+ /** The pictures attached as image parts, in order: empty unless `pictures` was given and one qualified. */
369
+ pictures: BundlePicture[];
370
+ /**
371
+ * The user message as content parts, for a request that takes pictures: the content's opening line and its text,
372
+ * then each attached picture as an image part (a `data:image/jpeg;base64,` address, never a web address), then the
373
+ * content's closing line and the task again, so the pictures sit inside the delimited block. Its text parts, joined
374
+ * with a line break, are `user`. With no picture attached it is one text part holding `user`.
375
+ */
376
+ user_parts: RenderedUserPart[];
280
377
  }
281
378
  /** Which fixed card a message calls for. */
282
379
  export type FixedCardKind = 'election' | 'crisis';
@@ -351,3 +448,122 @@ export interface FixedCardMatch {
351
448
  * 'card_then_answer' shows the card first, then the turn may go on to a model answer.
352
449
  */
353
450
  export type FixedCardAnswer = 'card_only' | 'card_then_answer';
451
+ /**
452
+ * How a message is sent: Sealed alone, or 'both' (D3: the same prompt to Standard and to Sealed, side by side). 'both'
453
+ * with encrypted-chat messages throws: an encrypted-chat ask is Sealed only (G21).
454
+ */
455
+ export type SealedTurnMode = 'sealed' | 'both';
456
+ /**
457
+ * Someone else's content in a Sealed message, by where it came from:
458
+ * - 'public_post': a post its author made public, as the post in a George ask, an attached post, a quote or a chat's
459
+ * subject (G13d);
460
+ * - 'members_only_post': a post in a group that is not public, in any of those places;
461
+ * - 'chat_messages': messages picked from a chat;
462
+ * - 'encrypted_chat': messages from an encrypted chat (G21). Sealed only: with mode 'both' it throws.
463
+ */
464
+ export type SealedContentKind = 'public_post' | 'members_only_post' | 'chat_messages' | 'encrypted_chat';
465
+ export declare const SEALED_CONTENT_KINDS: readonly SealedContentKind[];
466
+ /**
467
+ * One Sealed message, as the app is about to send it. Choices that send something (search, memory, the chip, the tick,
468
+ * About you, Tinfoil's page-open limit) count only when `true`. The six facts the caps cannot see for themselves
469
+ * (`others_content`, `phone_pictures`, `temporary`, `searched_earlier`, `phone_pictures_earlier`, `earlier_messages`)
470
+ * are required: absent or null throws, and the four flags count as set for any value but `false`. A `mode`,
471
+ * `others_content` or `phone_pictures` this function cannot read throws a TypeError, and so does mode 'both' with
472
+ * 'encrypted_chat' content (G21: Sealed only).
473
+ */
474
+ export interface SealedTurnInput {
475
+ mode: SealedTurnMode;
476
+ /** "Search the web" is on for this chat (the composer's switch). */
477
+ search?: boolean | null;
478
+ /**
479
+ * Someone else's content in this message or anywhere earlier in this chat; a chat's subject counts for every message
480
+ * in it. Required: pass `[]` for a message of the member's own words only.
481
+ */
482
+ others_content: readonly SealedContentKind[];
483
+ /**
484
+ * The chat has earlier messages or answers. Required: pass `false` for the first message. It decides the
485
+ * 'search.question_only' line: a message that searches never carries the chat so far, and the member is told so.
486
+ */
487
+ earlier_messages: boolean;
488
+ /**
489
+ * A message earlier in this chat searched the web, so George's earlier answers may echo a web page. Required: pass
490
+ * `false` when none did. It stops memory suggestions (4.2, gate M3); it does not stop search or memory.
491
+ */
492
+ searched_earlier: boolean;
493
+ /**
494
+ * A message earlier in this chat carried a picture from the phone to Sealed, so George's earlier answers about it,
495
+ * which stay in the history (2.2), may echo words written in it. Required: pass `false` when none did. It stops
496
+ * memory suggestions (4.2); it does not stop search or memory.
497
+ */
498
+ phone_pictures_earlier: boolean;
499
+ /** Sealed memory is on (Settings > George > What George remembers, "On this phone"). Off by default. */
500
+ memory?: boolean | null;
501
+ /**
502
+ * The header's Memory chip is on for this chat. Counts only when `others_content` is empty: memory is off in any
503
+ * ask or chat carrying someone else's content unless the member ticks `memory_tick` (George plan 4.7).
504
+ */
505
+ memory_in_chat?: boolean | null;
506
+ /**
507
+ * The member ticked "Use what George remembers" for this ask or chat (it starts off). The only thing that sends
508
+ * memory, or About you, with someone else's content; ignored when `others_content` is empty.
509
+ */
510
+ memory_tick?: boolean | null;
511
+ /** "Use these" is on for the About you fields ("How George talks to you"). */
512
+ about_you?: boolean | null;
513
+ /**
514
+ * How many pictures from the phone are attached: a whole number from 0 to 3 (a message carries at most 3 pictures in
515
+ * all, sealed-full-scope-v1 2.2, so the composer caps them). Required: pass `0` for none. Absent or null throws, so a
516
+ * caller that forgot it never searches beside a picture or drops one without its line; more than 3 throws.
517
+ */
518
+ phone_pictures: number;
519
+ /** A temporary Sealed chat. Required: pass `false` for a saved chat. */
520
+ temporary: boolean;
521
+ /**
522
+ * Tinfoil limits page opens for Minds' key to addresses from search results or the member's message
523
+ * (sealed-full-scope-v1 3.6, ask 3). Defaults to false. Set it only from a server switch, once Tinfoil confirms.
524
+ */
525
+ page_opens_limited?: boolean | null;
526
+ }
527
+ /**
528
+ * Why something the member turned on is off for this message, as the copy id the app shows (sealed-full-scope-v1
529
+ * 5.1 and 5.2):
530
+ * - 'search.off_mix': it carries memory, About you or a picture from the phone, so it doesn't search;
531
+ * - 'search.off_subject': it carries someone else's public post, and Tinfoil doesn't limit page opens yet (ask 3);
532
+ * - 'search.off_members': it carries a members-only post or picked chat messages, which never search;
533
+ * - 'search.e2ee': it carries encrypted-chat messages, which never search;
534
+ * - 'search.question_only': it searches, so it carries only the question, not the chat so far;
535
+ * - 'both.no_search': a Both message doesn't search;
536
+ * - 'both.no_photo': a Both message doesn't carry a picture from the phone.
537
+ */
538
+ export type SealedTurnReason = 'search.off_mix' | 'search.off_subject' | 'search.off_members' | 'search.e2ee' | 'search.question_only' | 'both.no_search' | 'both.no_photo';
539
+ export declare const SEALED_TURN_REASONS: readonly SealedTurnReason[];
540
+ /**
541
+ * What one Sealed message may carry. Someone else's content in the message itself (the post asked about) always goes.
542
+ * In a Both message it goes to the Standard half too, an ordinary Minds turn (2.6), whose bundle is built with mode
543
+ * 'standard' (that leaves out posts whose authors chose Sealed only). So these caps do not keep a public post, a
544
+ * members-only post or picked chat messages from Standard. Only encrypted-chat content is Sealed only: a Both message
545
+ * with it throws instead of returning caps.
546
+ */
547
+ export interface SealedTurnCaps {
548
+ /** Put `web_search_options`, with both of Tinfoil's filters, in the sealed body, and mark the request as one that may search. */
549
+ search: boolean;
550
+ /** Send the chat's earlier messages and George's earlier answers. Never with a message that searches. */
551
+ history: boolean;
552
+ /** Send the saved facts, in the sealed body (4.3). */
553
+ memory: boolean;
554
+ /** Send the About you fields, in the same system message as the facts. */
555
+ about_you: boolean;
556
+ /**
557
+ * The attached pictures from the phone may go. The picture checks (2.4) still decide each one. Never in Both, and
558
+ * never with encrypted-chat messages (G21 is one message of words; that surface has no Photo item, so no line).
559
+ */
560
+ phone_pictures: boolean;
561
+ /**
562
+ * A suggestion tagged in the answer may be offered for saving (4.2, gate M3). Never from a message that may hold
563
+ * someone else's words: a post, chat messages, this message's search results, a picture from the phone (it may be a
564
+ * screenshot), or an earlier answer built from a search or about a phone picture.
565
+ */
566
+ suggest_memory: boolean;
567
+ /** Copy ids for what the member turned on that this message leaves off, each once, in a fixed order. */
568
+ reasons: SealedTurnReason[];
569
+ }
@@ -9,3 +9,18 @@
9
9
  */
10
10
  export const ASSIST_INTENTS = ['explain', 'summarise', 'fact_context', 'translate', 'describe'];
11
11
  export const FIXED_CARD_LANGUAGES = ['en', 'es'];
12
+ export const SEALED_CONTENT_KINDS = [
13
+ 'public_post',
14
+ 'members_only_post',
15
+ 'chat_messages',
16
+ 'encrypted_chat',
17
+ ];
18
+ export const SEALED_TURN_REASONS = [
19
+ 'search.off_mix',
20
+ 'search.off_subject',
21
+ 'search.off_members',
22
+ 'search.e2ee',
23
+ 'search.question_only',
24
+ 'both.no_search',
25
+ 'both.no_photo',
26
+ ];
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './resources/discovery-learning.js';
2
2
  import { DiscoveryResource } from './resources/discovery.js';
3
3
  export * from './resources/discovery.js';
4
4
  export * from './feed-definition.js';
5
+ export * from './social-protocol-ids.js';
5
6
  import { AuthResource } from './resources/auth.js';
6
7
  import { PostsResource } from './resources/posts.js';
7
8
  import { UsersResource } from './resources/users.js';
@@ -67,6 +68,7 @@ import { FeedsResource } from './resources/feeds.js';
67
68
  import { AccountsResource } from './resources/accounts.js';
68
69
  import { SignalsResource } from './resources/signals.js';
69
70
  import { SealedResource } from './resources/sealed.js';
71
+ import { PrivacyResource } from './resources/privacy.js';
70
72
  import { RealtimeClient } from './realtime.js';
71
73
  import type { RecursivConfig } from './types.js';
72
74
  export declare class Recursiv {
@@ -144,6 +146,8 @@ export declare class Recursiv {
144
146
  readonly signals: SignalsResource;
145
147
  /** Sealed mode's config and transport: targets, models, allowance, the attestation relay and the sealed send (no crypto; flag-gated). */
146
148
  readonly sealed: SealedResource;
149
+ /** Which platform privacy facts the deployed API's build enforces (pair with `@recursiv/sdk/privacy`). */
150
+ readonly privacy: PrivacyResource;
147
151
  readonly realtime: RealtimeClient;
148
152
  constructor(config?: Partial<RecursivConfig>);
149
153
  /**
@@ -218,13 +222,13 @@ export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
218
222
  export type { PublicSearchPage, PublicSearchTab, SearchAnswer, SearchGroup, SearchLadder, SearchOmitReason, SearchParams, SearchPerson, SearchPost, SearchRelated, SearchResponse, SearchSection, SearchStage, SearchStory, SearchTopic, SearchVia, } from './resources/search.js';
219
223
  export { BOOKMARK_MERGE_MAX_ITEMS, BookmarkCollectionsResource, BookmarksResource } from './resources/bookmarks.js';
220
224
  export { FEED_TOP_NETWORKS, FeedsResource } from './resources/feeds.js';
221
- export type { FeedStoriesParams, FeedStoriesResponse, FeedStory, FeedTopExplain, FeedTopItem, FeedTopMeta, FeedTopNetwork, FeedTopNetworkCard, FeedTopNetworkEntry, FeedTopParams, FeedTopResponse, FeedTopTarget, PublicFeedTopMeta, PublicFeedTopParams, PublicFeedTopResponse, } from './resources/feeds.js';
225
+ export type { FeedStoriesParams, FeedStoriesResponse, FeedStory, FeedTopExplain, FeedTopItem, FeedTopMeta, FeedTopNetwork, FeedTopNetworkCard, FeedTopNetworkEntry, FeedTopNetworkMap, FeedTopParams, FeedTopResponse, FeedTopTarget, PublicFeedTopMeta, PublicFeedTopParams, PublicFeedTopResponse, } from './resources/feeds.js';
222
226
  export type { BookmarkCollection, BookmarkCollectionInput, BookmarkCollectionKind, BookmarkCollectionPatch, BookmarkCollectionsList, BookmarkCollectionTarget, BookmarkCollectionVisibility, BookmarkedPost, BookmarkInput, BookmarkItem, BookmarkKey, BookmarkKeyRow, BookmarkKeysPage, BookmarkKind, BookmarkMergeItem, BookmarkMergeResult, BookmarkProtocol, BookmarkRequestOptions, BookmarksPage, FiledBookmark, RemovedBookmarkCollection, SavedBookmark, UnfiledBookmark, UnsavedBookmark, } from './resources/bookmarks.js';
223
227
  export { AccountsResource } from './resources/accounts.js';
224
- export { SIGNAL_BATCH_MAX, SignalsResource } from './resources/signals.js';
225
- export type { SignalBatchResult, SignalEventInput, SignalEventType, SignalNotRecordedReason, SignalRecordResult, SignalSendOptions, } from './resources/signals.js';
228
+ export { SIGNAL_BATCH_MAX, SignalsResource, newClientEventId } from './resources/signals.js';
229
+ export type { ClearViewingHistoryResult, SignalBatchResult, SignalEventInput, SignalEventType, SignalExit, SignalMetadata, SignalNotRecordedReason, SignalRecordResult, SignalRejection, SignalSendOptions, SignalSurface, } from './resources/signals.js';
226
230
  export { SEALED_ALLOWANCE_REMAINING_HEADER, SEALED_REFUSAL_HEADER, SealedResource, SealedTransportError, } from './resources/sealed.js';
227
- export type { SealedAllowance, SealedAttestationInput, SealedConfig, SealedModel, SealedSendInput, SealedTarget, SealedTargetKind, SealedTransportErrorCode, } from './resources/sealed.js';
231
+ export type { SealedAllowance, SealedAttestationInput, SealedConfig, SealedModel, SealedPlan, SealedPurpose, SealedQuotaDetails, SealedSendInput, SealedTarget, SealedTargetKind, SealedTransportErrorCode, } from './resources/sealed.js';
228
232
  export type { SiblingAccount, SiblingAccountsResponse, SwitchAccountResult, } from './resources/accounts.js';
229
233
  export type { LinkPreview, LinkPreviewResponse, LinkPreviewSource, } from './resources/link-preview.js';
230
234
  export type { AgentCapabilityConsentRequirement, AgentCapabilityDataSensitivity, AgentCapabilityDomain, AgentCapabilityExportBoundary, AgentCapabilityRetentionClass, AgentCapabilitySubdomain, AgentCapabilitySubject, AgentCapabilityTrustTier, AgentToolAudience, AgentToolScope, BrowserUseRunTaskInput, ProjectBrainSettings, ProjectToolBundleClassification, ProjectToolBundleKey, ProjectToolPermission, ProjectToolPermissionOverrides, UpdateProjectSettingsInput, } from './resources/project-brain.js';
@@ -238,8 +242,8 @@ export type { LinkedTokenWallet, PayoutState, TokenBalance, TokenLedgerEntry } f
238
242
  export { BoostsResource } from './resources/boosts.js';
239
243
  export type { BoostBalance, BoostBalanceResponse, BoostCampaign, BoostCampaignResponse, BoostEventResult, BoostLedgerEntry, BoostLedgerKind, BoostPlanCredit, BoostRejectionReason, BoostReviewStatus, BoostStatus, BoostTopupCheckout, BoostTopupConfirmation, BoostTopupLimits, } from './resources/boosts.js';
240
244
  export { ProtocolsResource } from './resources/protocols.js';
241
- export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
242
- export type { SocialProfile, SocialBridge, SocialSubscription, SocialSubscriptionChange, SocialProfilePage, SocialRadar, SocialRadarCluster, SocialRadarMember, SocialRadarParams, SocialRadarPosts, SocialRadarStory, SocialRadarStoryArchive, ViralBaseline, ViralItem, ViralItemFields, ViralItemSpread, ViralItemVelocity, ViralLabel, ViralMindsCard, ViralMindsItem, ViralNetwork, ViralOpenProtocol, ViralProtocol, ViralProvider, ViralReadMeta, ViralReadParams, ViralReadResponse, ViralReadStatus, ViralRef, ViralSocialItem, SocialNetwork, SocialPost, SocialConversation, SocialTrend, SocialTrendProvenance, SocialTrends, SocialTrendSourceIndex, SocialTrendFeed, SocialPopularProfiles, SocialAuthorFeed, SocialFollowingFeed, SocialFollowingSource, SearchPublicProfilesParams, SearchPublicPostsParams, SocialPostSearch, HostedProtocolConnections, HostedProtocol, HostedProtocolIdentity, HostedNostrChallenge, HostedNostrIdentityProof, NativeNostrPrepareInput, NativeNostrPrepared, NativeNostrAccount, NativeNostrPostState, NativeNostrReceipt, NativeSocialProtocol, FederationIdentity, FederationIdentityView, NativeSocialAccount, NativeSocialCallbackInput, NativeReplyPrepareInput, NativePostPrepareInput, NativeMediaInput, NativeMediaItem, NativePostBatch, NativePostQuote, NativePostHistory, NativeDelegatedPostHistoryItem, NativeNostrPostHistoryItem, NativeFollowSourceInput, NativeFollowPrepareInput, NativeFollowTarget, NativeFollowReceipt, NativeFollowState, NativeFollowAccount, NativeFollowStates, NativeFollowReview, NativeLikeSourceInput, NativeRepostSourceInput, NativeLikePrepareInput, NativeRepostPrepareInput, NativeLikeTarget, NativeRepostTarget, NativeLikeReceipt, NativeRepostReceipt, NativeLikeState, NativeRepostState, NativeLikeReview, NativeRepostReview, NativeReplyReceipt, NativeReplyBatch, NativeReplyHistory, NativeDelegatedReplyHistoryItem, NativeNostrReplyResult, NativeNostrReplyHistoryItem, NativeReplyRemovalReceipt, NativeReplyRemovalPreview, SocialSourceRef, SocialSourceControl, SocialSourceControlDisplay, SocialSourceControlChange, HostedPostPreview, ConnectHostedIdentityInput, CreateHostedIdentityInput, CreatedHostedProtocolIdentity, PreviewHostedPostInput, PublishHostedPostInput, ListProtocolCandidatesParams, ProtocolAdapterMaturity, ProtocolAdapterMetadata, ProtocolCandidateListResponse, ProtocolCandidatePageMeta, ProtocolCapabilityOperation, ProtocolCapabilityStatus, ProtocolCollectionStatus, ProtocolIngestionActivityReason, ProtocolIngestionCircuitHealth, ProtocolIngestionDeadLetterGroup, ProtocolIngestionHealthPosition, ProtocolIngestionHealthReport, ProtocolIngestionHealthRuntime, ProtocolIngestionHealthSection, ProtocolIngestionLaneActivity, ProtocolIngestionLaneCurrentJob, ProtocolIngestionLaneDeadLetters, ProtocolIngestionLaneHealth, ProtocolIngestionLaneJobs, ProtocolIngestionReplayResult, ProtocolIngestionStatus, ProtocolQuarantinedCandidate, ProtocolRefreshResult, ProtocolSettings, ProtocolSettingsUpdateResult, ReplayProtocolIngestionJobInput, UpdateSettingsInput as UpdateProtocolSettingsInput, } from './resources/protocols.js';
245
+ export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, SOCIAL_FOLLOWING_SOURCE_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
246
+ export type { SocialProfile, SocialBridge, SocialSubscription, SocialSubscriptionChange, SocialProfilePage, SocialRadar, SocialRadarCluster, SocialRadarMember, SocialRadarParams, SocialRadarSourceKind, SocialRadarPosts, SocialRadarStory, SocialRadarStoryArchive, ViralBaseline, ViralItem, ViralItemFields, ViralItemSpread, ViralItemVelocity, ViralLabel, ViralMindsCard, ViralMindsItem, ViralNetwork, ViralOpenProtocol, ViralProtocol, ViralProvider, ViralReadMeta, ViralReadParams, ViralReadResponse, ViralReadStatus, ViralRef, ViralSocialItem, SocialNetwork, SocialPost, SocialConversation, SocialTrend, SocialTrendProvenance, SocialTrends, SocialTrendSourceIndex, SocialTrendFeed, SocialPopularProfiles, SocialAuthorFeed, SocialFollowingFeed, SocialFollowingSource, SocialFollowingSourceStatus, SearchPublicProfilesParams, SearchPublicPostsParams, SocialPostSearch, HostedProtocolConnections, HostedProtocol, HostedProtocolIdentity, HostedNostrChallenge, HostedNostrIdentityProof, NativeNostrPrepareInput, NativeNostrPrepared, NativeNostrAccount, NativeNostrPostState, NativeNostrReceipt, NativeSocialProtocol, FederationIdentity, FederationIdentityView, NativeSocialAccount, NativeNetwork, NativeNetworkState, NativeNetworkPresence, NativeNetworkActivation, NativeNetworkOff, SetNativeNetworkInput, NativeSocialCallbackInput, NativeReplyPrepareInput, NativePostPrepareInput, NativeMediaInput, NativeMediaItem, NativePostBatch, NativePostQuote, NativePostHistory, NativeDelegatedPostHistoryItem, NativeNostrPostHistoryItem, NativeFollowSourceInput, NativeFollowPrepareInput, NativeFollowTarget, NativeFollowReceipt, NativeFollowState, NativeFollowAccount, NativeFollowStates, NativeFollowReview, NativeLikeSourceInput, NativeRepostSourceInput, NativeLikePrepareInput, NativeRepostPrepareInput, NativeLikeTarget, NativeRepostTarget, NativeLikeReceipt, NativeRepostReceipt, NativeLikeState, NativeRepostState, NativeLikeReview, NativeRepostReview, NativeReplyReceipt, NativeReplyBatch, NativeReplyHistory, NativeDelegatedReplyHistoryItem, NativeNostrReplyResult, NativeNostrReplyHistoryItem, NativeReplyRemovalReceipt, NativeReplyRemovalPreview, SocialSourceRef, SocialSourceControl, SocialSourceControlDisplay, SocialSourceControlChange, HostedPostPreview, ConnectHostedIdentityInput, CreateHostedIdentityInput, CreatedHostedProtocolIdentity, PreviewHostedPostInput, PublishHostedPostInput, ListProtocolCandidatesParams, ProtocolAdapterMaturity, ProtocolAdapterMetadata, ProtocolCandidateListResponse, ProtocolCandidatePageMeta, ProtocolCapabilityOperation, ProtocolCapabilityStatus, ProtocolCollectionStatus, ProtocolIngestionActivityReason, ProtocolIngestionCircuitHealth, ProtocolIngestionDeadLetterGroup, ProtocolIngestionHealthPosition, ProtocolIngestionHealthReport, ProtocolIngestionHealthRuntime, ProtocolIngestionHealthSection, ProtocolIngestionLaneActivity, ProtocolIngestionLaneCurrentJob, ProtocolIngestionLaneDeadLetters, ProtocolIngestionLaneHealth, ProtocolIngestionLaneJobs, ProtocolIngestionReplayResult, ProtocolIngestionStatus, ProtocolQuarantinedCandidate, ProtocolRefreshResult, ProtocolSettings, ProtocolSettingsUpdateResult, ReplayProtocolIngestionJobInput, UpdateSettingsInput as UpdateProtocolSettingsInput, } from './resources/protocols.js';
243
247
  export { InboxResource } from './resources/inbox.js';
244
248
  export { NetworkResource } from './resources/network.js';
245
249
  export { SimulatorResource } from './resources/simulator.js';
@@ -273,3 +277,5 @@ export type { PrepareHostedServiceInput, HostedServiceScope, HostedServiceOperat
273
277
  export { ASSISTANT_SURFACE_IDS, assistantSurfaceOn, assistantSurfaces, isAssistantSurfaceId, } from './assistant-surfaces.js';
274
278
  export type { AssistantSettings, AssistantSettingsUpdate, AssistantSurfaceId, AssistantSurfaces, } from './assistant-surfaces.js';
275
279
  export type { CurrentUser } from './resources/users.js';
280
+ export { PrivacyResource } from './resources/privacy.js';
281
+ export type { LiveFactOptions, PrivacyCapabilities } from './privacy/index.js';
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from './resources/discovery-learning.js';
2
2
  import { DiscoveryResource } from './resources/discovery.js';
3
3
  export * from './resources/discovery.js';
4
4
  export * from './feed-definition.js';
5
+ export * from './social-protocol-ids.js';
5
6
  import { HttpClient } from './client.js';
6
7
  import { AuthResource } from './resources/auth.js';
7
8
  import { PostsResource } from './resources/posts.js';
@@ -68,6 +69,7 @@ import { FeedsResource } from './resources/feeds.js';
68
69
  import { AccountsResource } from './resources/accounts.js';
69
70
  import { SignalsResource } from './resources/signals.js';
70
71
  import { SealedResource } from './resources/sealed.js';
72
+ import { PrivacyResource } from './resources/privacy.js';
71
73
  import { RealtimeClient } from './realtime.js';
72
74
  export class Recursiv {
73
75
  /** Shared transport, kept so the client name can be set after construction. */
@@ -145,6 +147,8 @@ export class Recursiv {
145
147
  signals;
146
148
  /** Sealed mode's config and transport: targets, models, allowance, the attestation relay and the sealed send (no crypto; flag-gated). */
147
149
  sealed;
150
+ /** Which platform privacy facts the deployed API's build enforces (pair with `@recursiv/sdk/privacy`). */
151
+ privacy;
148
152
  realtime;
149
153
  constructor(config) {
150
154
  const client = new HttpClient(config);
@@ -214,6 +218,7 @@ export class Recursiv {
214
218
  this.accounts = new AccountsResource(client);
215
219
  this.signals = new SignalsResource(client);
216
220
  this.sealed = new SealedResource(client);
221
+ this.privacy = new PrivacyResource(client);
217
222
  this.realtime = new RealtimeClient(client);
218
223
  this.#http = client;
219
224
  }
@@ -274,7 +279,7 @@ export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
274
279
  export { BOOKMARK_MERGE_MAX_ITEMS, BookmarkCollectionsResource, BookmarksResource } from './resources/bookmarks.js';
275
280
  export { FEED_TOP_NETWORKS, FeedsResource } from './resources/feeds.js';
276
281
  export { AccountsResource } from './resources/accounts.js';
277
- export { SIGNAL_BATCH_MAX, SignalsResource } from './resources/signals.js';
282
+ export { SIGNAL_BATCH_MAX, SignalsResource, newClientEventId } from './resources/signals.js';
278
283
  export { SEALED_ALLOWANCE_REMAINING_HEADER, SEALED_REFUSAL_HEADER, SealedResource, SealedTransportError, } from './resources/sealed.js';
279
284
  export { OrganizationSettingsResource } from './resources/organization-settings.js';
280
285
  export { ProjectSettingsResource } from './resources/project-settings.js';
@@ -283,7 +288,7 @@ export { UploadsResource } from './resources/uploads.js';
283
288
  export { WalletResource } from './resources/wallet.js';
284
289
  export { BoostsResource } from './resources/boosts.js';
285
290
  export { ProtocolsResource } from './resources/protocols.js';
286
- export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
291
+ export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, SOCIAL_FOLLOWING_SOURCE_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
287
292
  export { InboxResource } from './resources/inbox.js';
288
293
  export { NetworkResource } from './resources/network.js';
289
294
  export { SimulatorResource } from './resources/simulator.js';
@@ -303,3 +308,4 @@ export { RecursivError, AuthenticationError, AuthorizationError, LegacyHandoffEr
303
308
  export { parseSSE } from './lib/sse.js';
304
309
  export * from './lib/webhooks.js';
305
310
  export { ASSISTANT_SURFACE_IDS, assistantSurfaceOn, assistantSurfaces, isAssistantSurfaceId, } from './assistant-surfaces.js';
311
+ export { PrivacyResource } from './resources/privacy.js';