@mikedown/core 0.3.0 → 0.4.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.
- package/CHANGELOG.md +12 -1
- package/README.md +1 -1
- package/dist/ai/engines-page.d.ts +11 -4
- package/dist/ai/engines-page.js +5 -4
- package/dist/ai/index.d.ts +1201 -10
- package/dist/ai/index.js +297 -8
- package/dist/{ai-ui-C7ENTWWU.js → ai-ui-QFYFN73D.js} +3165 -138
- package/dist/ai-ui-QFYFN73D.js.map +1 -0
- package/dist/{chunk-QDVY7WW6.js → chunk-APPBNQEY.js} +53 -2
- package/dist/chunk-APPBNQEY.js.map +1 -0
- package/dist/{chunk-7A5HEPLK.js → chunk-DWXGWVA3.js} +850 -12
- package/dist/chunk-DWXGWVA3.js.map +1 -0
- package/dist/{chunk-JZWKEBCI.js → chunk-IWCXWUWW.js} +3260 -201
- package/dist/chunk-IWCXWUWW.js.map +1 -0
- package/dist/{chunk-LXZG7IKN.js → chunk-N4N54LK2.js} +2 -2
- package/dist/chunk-N4N54LK2.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +399 -38
- package/dist/index.js.map +1 -1
- package/dist/schema-DVfssxQX.d.ts +100 -0
- package/dist/styles.css +943 -4
- package/dist/{types-CsVNVSNY.d.ts → types-2TZErbJr.d.ts} +25 -3
- package/dist/{types-CgEeIUhi.d.ts → types-DO8UBybZ.d.ts} +316 -7
- package/package.json +1 -1
- package/dist/ai-ui-C7ENTWWU.js.map +0 -1
- package/dist/chunk-7A5HEPLK.js.map +0 -1
- package/dist/chunk-JZWKEBCI.js.map +0 -1
- package/dist/chunk-LXZG7IKN.js.map +0 -1
- package/dist/chunk-QDVY7WW6.js.map +0 -1
- package/dist/schema-DYzxkuSb.d.ts +0 -46
package/dist/ai/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
export { a as AI_SETTINGS_KEYS, A as AiSettingsPatch, P as ParseAiSettingsOptions, g as
|
|
1
|
+
import { c as AiModelCapabilities, d as AiCapabilityFlag, e as AiSendsScope, f as AiFeatureSettings, g as AiLocality, h as AiEngineConfig, i as AiEngineKind, j as AiModelConfig, k as AiDiscoveredModel, l as AiApiKeyFile, m as AiDocsOptions, A as AiSettings, a as AiEngineStatus, n as AiFinishReason, o as AiUsage, p as AiErrorCode, q as AiCompletionResult, r as AiCompletionRequest, s as AiMessage, t as AiError, u as AiDocsLink, v as AiDocsIndex, w as AiDocsPage, x as AiDocsHome, y as AiDocsSectionRef, z as AiDocsSection, B as AiDocBaseStatus, b as MikeDownDocsHost, C as AiDocsNavigateBy, D as AiConsentRecord, E as AiLocalServerProbe, F as AiHardwareInfo, G as AiHostEngineProbe } from '../types-DO8UBybZ.js';
|
|
2
|
+
export { H as AI_CAPABILITY_FLAGS, I as AI_DOCS_MAX_HOPS_DEFAULT, J as AI_DOCS_MAX_HOPS_MAX, K as AI_DOCS_MAX_HOPS_MIN, L as AI_DOCS_NAVIGATE_BY, N as AI_DOCS_NAVIGATE_BY_DEFAULT, O as AI_DOCS_SOURCE_SHARE_DEFAULT, P as AI_DOCS_SOURCE_SHARE_MAX, Q as AI_DOCS_SOURCE_SHARE_MIN, R as AI_ENGINE_KINDS, S as AI_ERROR_CODES, T as AI_FALLBACK_MODES, U as AI_HOST_ENGINE_KINDS, V as AI_TURN_GRANT_MAX_USES, W as AiCapabilitiesSource, X as AiCompletionTurn, Y as AiConsentAbout, Z as AiConsentReply, _ as AiDocBase, $ as AiDocHomeKind, a0 as AiDocRootStatus, a1 as AiDocsHeading, a2 as AiDocsSettings, a3 as AiEngineStatusModel, a4 as AiFallbackMode, a5 as AiFeatureSetting, a6 as AiGhostTextOptions, a7 as AiGhostTrigger, a8 as AiKeySource, a9 as AiLocalitySetting, aa as AiMessagePart, ab as AiRoute, ac as AiRouting, ad as AiServedBy, ae as AiTiming, af as AiTurnConsentAbout, ag as DEFAULT_CONTEXT_TOKENS, M as MikeDownAiHost, ah as ProviderAdapter } from '../types-DO8UBybZ.js';
|
|
3
|
+
export { a as AI_SETTINGS_KEYS, A as AiSettingsPatch, D as DocRootCheck, G as GHOST_DELAY_MS_DEFAULT, b as GHOST_DELAY_MS_MAX, c as GHOST_DELAY_MS_MIN, d as GHOST_MAX_TOKENS_DEFAULT, e as GHOST_MAX_TOKENS_MAX, f as GHOST_MAX_TOKENS_MIN, P as ParseAiSettingsOptions, g as checkDocRoot, h as docRootKey, i as generateAiId, j as ghostTextOptions, k as isHostEngineKind, l as isKnownEngineKind, n as normalizeDocHomeFile, p as parseAiSettings, m as parseDocBases, o as parseDocsOptions, r as resolveDocsSettings, s as serializeAiSettings } from '../schema-DVfssxQX.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Task taxonomy. A feature names a task; the router picks the engine and
|
|
@@ -390,6 +390,8 @@ declare function localDetectTarget(candidate: {
|
|
|
390
390
|
* start from them without loading the rest of the AI layer (see `ai-lite.ts`).
|
|
391
391
|
*/
|
|
392
392
|
|
|
393
|
+
/** The advanced docs options before the user changes any. */
|
|
394
|
+
declare function defaultAiDocsOptions(): AiDocsOptions;
|
|
393
395
|
declare function defaultAiSettings(): AiSettings;
|
|
394
396
|
|
|
395
397
|
/**
|
|
@@ -451,6 +453,8 @@ interface ResolveRouteOptions {
|
|
|
451
453
|
feature: string;
|
|
452
454
|
/** Route this task instead of the feature's. */
|
|
453
455
|
task?: string;
|
|
456
|
+
/** Inline suggestions: reject every cloud engine (`cloudBlocked`), whatever Allow cloud and consent say. */
|
|
457
|
+
localOnly?: boolean;
|
|
454
458
|
}
|
|
455
459
|
declare function resolveRoute(settings: AiSettings, statuses: readonly AiEngineStatus[], consent: AiConsentState, opts: ResolveRouteOptions): AiRouteResolution;
|
|
456
460
|
|
|
@@ -811,7 +815,8 @@ declare function nearestThinkingLevel(kind: string, level: AiThinkingLevel | nul
|
|
|
811
815
|
type AiThinkingJob = string;
|
|
812
816
|
/**
|
|
813
817
|
* The level MikeDown picks for a job when the dial is on Default (Q6): Off
|
|
814
|
-
* for the short edits, null (the model's
|
|
818
|
+
* for the short edits and the docs chat's `navigate` hops, null (the model's
|
|
819
|
+
* own) for everything else, the docs chat's `answer` call included.
|
|
815
820
|
*/
|
|
816
821
|
declare function taskThinkingDefault(job: string | undefined): AiThinkingLevel | null;
|
|
817
822
|
interface ResolvedThinkingLevel {
|
|
@@ -1114,8 +1119,21 @@ interface HeadingOutlineEntry {
|
|
|
1114
1119
|
level: number;
|
|
1115
1120
|
text: string;
|
|
1116
1121
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1122
|
+
interface HeadingWithOffsets extends HeadingOutlineEntry {
|
|
1123
|
+
/** Offset of the heading line's first character. */
|
|
1124
|
+
start: number;
|
|
1125
|
+
/** Offset just past the heading line's end of line (the next line's start, or the text length). */
|
|
1126
|
+
end: number;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Heading levels, texts and line offsets, skipping frontmatter and fenced code.
|
|
1130
|
+
* `limit` stops after that many headings (the documentation index keeps 1000).
|
|
1131
|
+
*/
|
|
1132
|
+
declare function headingsWithOffsets(markdown: string, limit?: number): HeadingWithOffsets[];
|
|
1133
|
+
/** Heading levels and texts, skipping frontmatter and fenced code. `limit` as in `headingsWithOffsets`. */
|
|
1134
|
+
declare function headingsOutline(markdown: string, limit?: number): HeadingOutlineEntry[];
|
|
1135
|
+
/** Offset just past the leading frontmatter block (0 when there is none). */
|
|
1136
|
+
declare function frontmatterEndOffset(markdown: string): number;
|
|
1119
1137
|
/**
|
|
1120
1138
|
* Keep the frontmatter and as many whole leading sections as fit in
|
|
1121
1139
|
* `contextTokens - outputTokens - reserveTokens` (at `CHARS_PER_TOKEN`
|
|
@@ -1272,6 +1290,1172 @@ type ParsedPropertySuggestions = {
|
|
|
1272
1290
|
*/
|
|
1273
1291
|
declare function parsePropertySuggestions(raw: string, existing: readonly AiFrontmatterEntry[], vocabulary: readonly string[]): ParsedPropertySuggestions;
|
|
1274
1292
|
|
|
1293
|
+
/**
|
|
1294
|
+
* Inline suggestions ("ghost text", the `ghostText` feature). Pure: a chat
|
|
1295
|
+
* "continue" prompt sent to every model (decision D4; the wire has no FIM
|
|
1296
|
+
* path). The text before the caret is the user turn; the text after it rides
|
|
1297
|
+
* in an `<after>` tag so the model stops where the existing text resumes.
|
|
1298
|
+
*/
|
|
1299
|
+
|
|
1300
|
+
/** Which kind of text block the caret is in; steers the continuation's shape. */
|
|
1301
|
+
type GhostBlockKind = 'paragraph' | 'heading' | 'listItem' | 'blockquote';
|
|
1302
|
+
/** Default and bounds for the output budget (tokens). */
|
|
1303
|
+
declare const CONTINUE_DEFAULT_MAX_TOKENS = 48;
|
|
1304
|
+
declare const CONTINUE_MIN_MAX_TOKENS = 8;
|
|
1305
|
+
declare const CONTINUE_MAX_MAX_TOKENS = 256;
|
|
1306
|
+
declare const CONTINUE_SYSTEM_PROMPT: string;
|
|
1307
|
+
interface ContinuePromptInput {
|
|
1308
|
+
/** The document text before the caret (see `ghostContext`). */
|
|
1309
|
+
before: string;
|
|
1310
|
+
/** The document text after the caret, possibly empty. */
|
|
1311
|
+
after: string;
|
|
1312
|
+
blockKind?: GhostBlockKind;
|
|
1313
|
+
}
|
|
1314
|
+
declare function buildContinueMessages(input: ContinuePromptInput): AiMessage[];
|
|
1315
|
+
/**
|
|
1316
|
+
* Output budget for a request: the `features.ghostText.maxTokens` setting
|
|
1317
|
+
* (default 48), rounded and clamped to 8 to 256. A bad value gets the default.
|
|
1318
|
+
*/
|
|
1319
|
+
declare function continueMaxTokens(setting?: number | null): number;
|
|
1320
|
+
|
|
1321
|
+
/**
|
|
1322
|
+
* The text a ghost-text request sends (decision D3): the text around the
|
|
1323
|
+
* cursor. Pure: given the document's markdown and the caret's offset in it,
|
|
1324
|
+
* return the last `GHOST_BEFORE_CHARS` characters before the caret verbatim
|
|
1325
|
+
* (a few paragraphs), a capped slice of the text after it, and, when the
|
|
1326
|
+
* document runs longer than that tail, a note listing the headings of
|
|
1327
|
+
* everything earlier so the model still knows where in the document it is.
|
|
1328
|
+
* The earlier text itself is never sent, however large the context window.
|
|
1329
|
+
* A small window shrinks the tail (never below 200 characters). Frontmatter
|
|
1330
|
+
* is never part of `before`.
|
|
1331
|
+
*/
|
|
1332
|
+
/** Characters before the caret that are always sent verbatim. */
|
|
1333
|
+
declare const GHOST_BEFORE_CHARS = 2400;
|
|
1334
|
+
/** Characters after the caret that are sent as the suffix. */
|
|
1335
|
+
declare const GHOST_AFTER_CHARS = 600;
|
|
1336
|
+
/** Tokens set aside for the system prompt, the tags and slack. */
|
|
1337
|
+
declare const GHOST_RESERVE_TOKENS = 400;
|
|
1338
|
+
/** Most headings listed for the sections left out. */
|
|
1339
|
+
declare const GHOST_OUTLINE_MAX_ITEMS = 40;
|
|
1340
|
+
/** Characters set aside for the list of headings left out. */
|
|
1341
|
+
declare const GHOST_OUTLINE_MAX_CHARS = 1000;
|
|
1342
|
+
/** Window assumed when a route reports none. */
|
|
1343
|
+
declare const GHOST_DEFAULT_CONTEXT_TOKENS = 4096;
|
|
1344
|
+
interface GhostContext {
|
|
1345
|
+
before: string;
|
|
1346
|
+
after: string;
|
|
1347
|
+
}
|
|
1348
|
+
interface GhostContextOptions {
|
|
1349
|
+
/** Tokens the answer may use (the `maxTokens` setting). Default 48. */
|
|
1350
|
+
outputTokens?: number;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* `before` and `after` for a caret at `caretOffset` in `markdown`. A caret
|
|
1354
|
+
* inside the frontmatter yields nothing (both empty), since there is nothing
|
|
1355
|
+
* to continue there. An `after` that is only whitespace is returned empty.
|
|
1356
|
+
*/
|
|
1357
|
+
declare function ghostContext(markdown: string, caretOffset: number, contextTokens: number, opts?: GhostContextOptions): GhostContext;
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* Clean up a ghost-text suggestion as it streams in (decisions D5 and D6).
|
|
1361
|
+
* Pure string work, no DOM. The controller calls `trimGhostSuggestion` on
|
|
1362
|
+
* the accumulated raw text after every token, so every rule here must give a
|
|
1363
|
+
* stable answer for a partial string.
|
|
1364
|
+
*/
|
|
1365
|
+
/** A suggestion longer than this is cut at the end of its next sentence. */
|
|
1366
|
+
declare const GHOST_SENTENCE_CUT_CHARS = 120;
|
|
1367
|
+
/** How many characters before the caret a suggestion may not repeat. */
|
|
1368
|
+
declare const GHOST_REPEAT_CHARS = 20;
|
|
1369
|
+
interface GhostTrimOptions {
|
|
1370
|
+
/** The caret is at the end of its text block (nothing after it in the block). */
|
|
1371
|
+
atBlockEnd: boolean;
|
|
1372
|
+
/** The text before the caret (only its tail is used). */
|
|
1373
|
+
before: string;
|
|
1374
|
+
}
|
|
1375
|
+
interface GhostTrimResult {
|
|
1376
|
+
/** The suggestion to show; empty means show nothing. */
|
|
1377
|
+
text: string;
|
|
1378
|
+
/** A stop rule fired (blank line, newline, sentence cut) or the suggestion was discarded: more tokens cannot change it, so the request can abort. */
|
|
1379
|
+
stopped: boolean;
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Apply the stop rules to `raw`: strip a stray code fence, cut at the first
|
|
1383
|
+
* blank line (and at the first newline when the caret is not at the end of
|
|
1384
|
+
* its block), cut after the first sentence that ends past 120 characters,
|
|
1385
|
+
* drop trailing whitespace, and discard a suggestion that is empty or starts
|
|
1386
|
+
* by repeating the last 20 characters before the caret. A space at the start
|
|
1387
|
+
* is dropped when the text before the caret already ends in whitespace.
|
|
1388
|
+
*/
|
|
1389
|
+
declare function trimGhostSuggestionDetailed(raw: string, opts: GhostTrimOptions): GhostTrimResult;
|
|
1390
|
+
/** The suggestion to show for the raw model output so far. Empty means nothing. */
|
|
1391
|
+
declare function trimGhostSuggestion(raw: string, opts: GhostTrimOptions): string;
|
|
1392
|
+
/**
|
|
1393
|
+
* The first word of `text` for "accept one word": its leading whitespace,
|
|
1394
|
+
* the word, and the one space or tab after it. The whole text when it has
|
|
1395
|
+
* no second word.
|
|
1396
|
+
*/
|
|
1397
|
+
declare function ghostAcceptWord(text: string): string;
|
|
1398
|
+
/**
|
|
1399
|
+
* The user typed `typed` while `text` was showing: the rest of the
|
|
1400
|
+
* suggestion when `typed` is exactly its start (case-sensitive), else null
|
|
1401
|
+
* (dismiss). An empty result means the whole suggestion was typed.
|
|
1402
|
+
*/
|
|
1403
|
+
declare function ghostPrefixMatch(text: string, typed: string): string | null;
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* Every cap and clamp of the documentation-base feature, in one place (S9).
|
|
1407
|
+
* Hosts and the loop import these; nothing else hardcodes a number. The hop
|
|
1408
|
+
* and share limits are M1's (`AI_DOCS_*` in `../types`), re-exported here so a
|
|
1409
|
+
* caller needs one import.
|
|
1410
|
+
*/
|
|
1411
|
+
|
|
1412
|
+
/** Markdown files indexed per base (decision 13). The walk stops at this many. */
|
|
1413
|
+
declare const DOCS_MAX_FILES = 5000;
|
|
1414
|
+
/** Bytes per file; a bigger file is skipped and counted in health. */
|
|
1415
|
+
declare const DOCS_MAX_FILE_BYTES: number;
|
|
1416
|
+
/** Bytes per section sent to a model (the host cuts at this and sets `truncated`). */
|
|
1417
|
+
declare const DOCS_MAX_SECTION_BYTES: number;
|
|
1418
|
+
/** Links in one hop-1 list. */
|
|
1419
|
+
declare const DOCS_MAX_LINKS = 200;
|
|
1420
|
+
/** Pages in the in-memory map used when a root has no home document. */
|
|
1421
|
+
declare const DOCS_MAX_MAP_ENTRIES = 400;
|
|
1422
|
+
/** Sections the keyword fallback returns. */
|
|
1423
|
+
declare const DOCS_KEYWORD_TOP = 20;
|
|
1424
|
+
/** Terms the keyword fallback uses from one query. */
|
|
1425
|
+
declare const DOCS_KEYWORD_MAX_TERMS = 12;
|
|
1426
|
+
/** Headings and links kept per page in the index (defence against one huge file). */
|
|
1427
|
+
declare const DOCS_MAX_HEADINGS_PER_PAGE = 1000;
|
|
1428
|
+
declare const DOCS_MAX_LINKS_PER_PAGE = 1000;
|
|
1429
|
+
/** Folders read per base while walking; the walk stops at this many and says so in health (S9). */
|
|
1430
|
+
declare const DOCS_MAX_DIRS = 20000;
|
|
1431
|
+
/** Heading text is cut to this many code points in the index and in sections (same rule on both hosts). */
|
|
1432
|
+
declare const DOCS_MAX_HEADING_CHARS = 200;
|
|
1433
|
+
/** A link target is cut to this many code points in the index. */
|
|
1434
|
+
declare const DOCS_MAX_LINK_TARGET_CHARS = 500;
|
|
1435
|
+
/**
|
|
1436
|
+
* How far (UTF-16 units) the link scanner looks for the end of a `<...>`
|
|
1437
|
+
* destination or a quoted title. A link whose destination or title does not
|
|
1438
|
+
* end within it is not a link. Link text is bounded by the same 300 as before.
|
|
1439
|
+
*/
|
|
1440
|
+
declare const DOCS_LINK_SCAN_UNITS = 1000;
|
|
1441
|
+
/** Link text between the brackets, in UTF-16 units (longer is not a link). */
|
|
1442
|
+
declare const DOCS_LINK_TEXT_UNITS = 300;
|
|
1443
|
+
/** Milliseconds one base's walk and index may take; past it the build ends and health says so (S9). */
|
|
1444
|
+
declare const DOCS_BUILD_BUDGET_MS = 30000;
|
|
1445
|
+
/** Candidate pages looked at while counting broken wikilinks, per base; past it the count stops (a lower bound). */
|
|
1446
|
+
declare const DOCS_MAX_LINK_WORK = 5000000;
|
|
1447
|
+
/** Ids taken from one navigation reply; the rest are dropped and counted. Model output is hostile. */
|
|
1448
|
+
declare const DOCS_MAX_READ_IDS_PER_HOP = 20;
|
|
1449
|
+
/** Characters of index text in one navigation prompt, whatever the route's context (several roots of 400 map entries add up). */
|
|
1450
|
+
declare const DOCS_MAX_NAV_CHARS = 96000;
|
|
1451
|
+
/** Longest id the loop looks up; anything longer is dropped unread. */
|
|
1452
|
+
declare const DOCS_MAX_ID_CHARS = 2048;
|
|
1453
|
+
/** Ids an Activity entry lists per field, each clipped; the count stays exact. */
|
|
1454
|
+
declare const DOCS_MAX_ACTIVITY_IDS = 100;
|
|
1455
|
+
declare const DOCS_MAX_ACTIVITY_ID_CHARS = 200;
|
|
1456
|
+
|
|
1457
|
+
/** Navigation calls before the answer, 1 to 5; anything not a number is the default (3). */
|
|
1458
|
+
declare function clampDocsHops(value: unknown): number;
|
|
1459
|
+
/** Percent of the route's context the answer's sections may take, 30 to 80; default 60. */
|
|
1460
|
+
declare function clampDocsSourceShare(value: unknown): number;
|
|
1461
|
+
/**
|
|
1462
|
+
* Cut a section's text to `DOCS_MAX_SECTION_BYTES` UTF-8 bytes on a code point
|
|
1463
|
+
* boundary. Scan (`secrets.ts`) the uncapped text first when you can, so a key
|
|
1464
|
+
* is never cut in half and slips through.
|
|
1465
|
+
*/
|
|
1466
|
+
declare function capSectionText(text: string, maxBytes?: number): {
|
|
1467
|
+
text: string;
|
|
1468
|
+
truncated: boolean;
|
|
1469
|
+
};
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* Small text helpers the documentation-base modules share. Every rule here is
|
|
1473
|
+
* written to be ported to Rust exactly (Desktop), so none of them leans on
|
|
1474
|
+
* locale behaviour or on a Unicode table.
|
|
1475
|
+
*/
|
|
1476
|
+
/**
|
|
1477
|
+
* Case folding used by ids, slugs and keyword ranking: ASCII `A` to `Z`
|
|
1478
|
+
* become `a` to `z`, every other code point is left alone. (No Unicode
|
|
1479
|
+
* lowercasing: `É` stays `É`, and `İ` or the Kelvin sign are not touched, so
|
|
1480
|
+
* JavaScript and Rust agree without a table.)
|
|
1481
|
+
*/
|
|
1482
|
+
declare function foldAscii(text: string): string;
|
|
1483
|
+
/**
|
|
1484
|
+
* Compare two strings by Unicode code point (the order UTF-8 bytes give, so
|
|
1485
|
+
* Rust's `str::cmp` agrees). JavaScript's `<` compares UTF-16 units, which
|
|
1486
|
+
* differs for characters above U+FFFF. Returns -1, 0 or 1.
|
|
1487
|
+
*/
|
|
1488
|
+
declare function cmpCodePoints(a: string, b: string): number;
|
|
1489
|
+
/**
|
|
1490
|
+
* The first `max` code points of `text` (the whole text when it has no more).
|
|
1491
|
+
* A surrogate pair counts as one and is never cut. Rust takes `chars().take(max)`.
|
|
1492
|
+
*/
|
|
1493
|
+
declare function clipCodePoints(text: string, max: number): string;
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Documentation-base index: root labels, page ids, heading slugs and the
|
|
1497
|
+
* builder hosts call. Pure, no DOM, no network.
|
|
1498
|
+
*
|
|
1499
|
+
* THE ID CONTRACT (A10). The VS Code host (TypeScript) and Desktop (Rust)
|
|
1500
|
+
* must produce byte-identical labels, ids and slugs; `test/ai-fixtures/docs/`
|
|
1501
|
+
* holds the cases both run. Nothing here uses a regex feature or Unicode table
|
|
1502
|
+
* Rust's standard library lacks.
|
|
1503
|
+
*
|
|
1504
|
+
* ROOT LABEL (`docsRootLabels`). A base has one or more root folders. Each
|
|
1505
|
+
* gets a label, the first segment of every id under it.
|
|
1506
|
+
* 1. Take the root path, split it on `/` and `\`, drop empty segments, take
|
|
1507
|
+
* the last one (the folder name). A path with no segment gives `root`.
|
|
1508
|
+
* 2. Replace `#` and every control character (below U+0020, and U+007F)
|
|
1509
|
+
* with `_`. A segment that is `.` or `..` becomes `root`.
|
|
1510
|
+
* 3. Make labels unique within the base, in configured order: the first
|
|
1511
|
+
* root keeps its label; a later root whose label is already taken gets
|
|
1512
|
+
* `-2`, `-3`, ... appended (the smallest suffix whose result is unused).
|
|
1513
|
+
* So `/a/docs` and `/b/docs` are `docs` and `docs-2`; a third `docs`
|
|
1514
|
+
* folder is `docs-3`. Comparison is exact (case-sensitive).
|
|
1515
|
+
* Labels are only unique inside one base. Ids from two bases can be equal, so
|
|
1516
|
+
* the loop always pairs an id with its base id.
|
|
1517
|
+
*
|
|
1518
|
+
* PAGE ID. `<root label>/<rel path>`, the path relative to the root with `/`
|
|
1519
|
+
* separators and exactly as the file system spells it (case kept), e.g.
|
|
1520
|
+
* `docs/guides/setup.md`. A rel path never starts with `/`, is never empty
|
|
1521
|
+
* and has no `.` or `..` segment (such a page is dropped from the index).
|
|
1522
|
+
*
|
|
1523
|
+
* SECTION ID. `<page id>#<slug>`, one per heading `headingsOutline` reports
|
|
1524
|
+
* (ATX headings outside frontmatter and fenced code, with non-empty text).
|
|
1525
|
+
* A bare page id means the whole page. File names can contain `#`, so
|
|
1526
|
+
* `parseDocsId` looks a full id up as a page first and only then splits at
|
|
1527
|
+
* the LAST `#` (slugs never contain `#`).
|
|
1528
|
+
*
|
|
1529
|
+
* HEADING SLUG (`docsSlug`, `docsSlugs`). From the heading text as
|
|
1530
|
+
* `headingsOutline` returns it (trimmed, closing `#`s removed):
|
|
1531
|
+
* 1. Walk the code points. ASCII `A-Z` become `a-z`. `a-z`, `0-9`, `_` and
|
|
1532
|
+
* `-` are kept. Whitespace (ASCII space, tab, LF, VT, FF, CR, plus
|
|
1533
|
+
* U+0085, U+00A0, U+1680, U+2000-U+200A, U+2028, U+2029, U+202F, U+205F,
|
|
1534
|
+
* U+3000) becomes `-`, one `-` per whitespace code point (not collapsed,
|
|
1535
|
+
* as GitHub does). Any other ASCII character is dropped. Every non-ASCII
|
|
1536
|
+
* code point is kept unchanged (no lowercasing), so non-Latin headings
|
|
1537
|
+
* still get a distinct slug.
|
|
1538
|
+
* 2. An empty result becomes `section`.
|
|
1539
|
+
* 3. Duplicates on one page, in document order: the first keeps its slug;
|
|
1540
|
+
* a later heading with a taken slug gets `-1`, `-2`, ... appended (the
|
|
1541
|
+
* smallest suffix whose result is unused, so `Setup`, `Setup`, `Setup 1`
|
|
1542
|
+
* give `setup`, `setup-1`, `setup-1-1`).
|
|
1543
|
+
* This equals GitHub's anchor for ASCII headings without odd collisions. Link
|
|
1544
|
+
* fragments are also matched against GitHub's anchor (`links.ts`).
|
|
1545
|
+
*
|
|
1546
|
+
* LIMITS (S9, the same on both hosts; `caps.ts`). A page keeps its first 1000
|
|
1547
|
+
* headings, and a heading's text is cut to its first 200 code points BEFORE
|
|
1548
|
+
* the slug is made, in the index and in `splitDocsSections` alike, so ids
|
|
1549
|
+
* agree. A link target is cut to its first 500 code points (`extractDocsLinks`).
|
|
1550
|
+
* Duplicate suffixes are handed out from a counter per base slug (same result
|
|
1551
|
+
* as "smallest unused suffix", in linear time).
|
|
1552
|
+
*
|
|
1553
|
+
* ORDER. `buildDocsIndex` sorts pages by root order, then rel path by code
|
|
1554
|
+
* point, so the same files give the same index on both hosts.
|
|
1555
|
+
*/
|
|
1556
|
+
|
|
1557
|
+
/** One unique label per root, in the order given (see the header for the rule). */
|
|
1558
|
+
declare function docsRootLabels(roots: readonly string[]): string[];
|
|
1559
|
+
/** The base slug of one heading text, before duplicate suffixes. */
|
|
1560
|
+
declare function docsSlug(text: string): string;
|
|
1561
|
+
/** Unique slugs for a page's heading texts, in document order. */
|
|
1562
|
+
declare function docsSlugs(texts: readonly string[]): string[];
|
|
1563
|
+
/** Heading text as the index and the sections keep it: at most `DOCS_MAX_HEADING_CHARS` code points. */
|
|
1564
|
+
declare function clipDocsHeading(text: string): string;
|
|
1565
|
+
/** GitHub's anchor for each heading text, with its `-1`, `-2` suffixes (used to match link fragments). */
|
|
1566
|
+
declare function githubAnchors(texts: readonly string[]): string[];
|
|
1567
|
+
/** `<root label>/<rel path>`. */
|
|
1568
|
+
declare function docsPageId(rootLabel: string, relPath: string): string;
|
|
1569
|
+
/** `<page id>#<slug>`. */
|
|
1570
|
+
declare function docsSectionId(pageId: string, slug: string): string;
|
|
1571
|
+
/** The root label of a page or section id: everything before the first `/`. */
|
|
1572
|
+
declare function docsIdRoot(id: string): string;
|
|
1573
|
+
/**
|
|
1574
|
+
* Split an id the model or host named into its page id and optional slug.
|
|
1575
|
+
* `hasPage` says whether a full string is a page in the host's own index; the
|
|
1576
|
+
* whole id is tried first (a file name may contain `#`), then the part before
|
|
1577
|
+
* the last `#`. Returns null when neither is a known page: never build a path
|
|
1578
|
+
* from an id that is not in the index (S1).
|
|
1579
|
+
*/
|
|
1580
|
+
declare function parseDocsId(id: string, hasPage: (pageId: string) => boolean): {
|
|
1581
|
+
pageId: string;
|
|
1582
|
+
slug?: string;
|
|
1583
|
+
} | null;
|
|
1584
|
+
/** True for a rel path a page may have: non-empty, relative, no empty, `.` or `..` segment, no NUL. */
|
|
1585
|
+
declare function isSafeRelPath(relPath: string): boolean;
|
|
1586
|
+
/** The file name without its `.md` / `.markdown` extension (any case). */
|
|
1587
|
+
declare function docsFileStem(relPath: string): string;
|
|
1588
|
+
/** A page as the host extracts it: no id, no slugs, no body. */
|
|
1589
|
+
interface AiDocsPageInput {
|
|
1590
|
+
/** The root's label (`docsRootLabels`). */
|
|
1591
|
+
root: string;
|
|
1592
|
+
/** Path relative to the root, `/` separators. */
|
|
1593
|
+
relPath: string;
|
|
1594
|
+
/** Frontmatter `title`, when there is one. Else the first heading, else the file name. */
|
|
1595
|
+
title?: string;
|
|
1596
|
+
/** From `headingsOutline(markdown)`. */
|
|
1597
|
+
headings: Array<{
|
|
1598
|
+
level: number;
|
|
1599
|
+
text: string;
|
|
1600
|
+
}>;
|
|
1601
|
+
/** Links as written (`AiDocsLink`). */
|
|
1602
|
+
links?: AiDocsLink[];
|
|
1603
|
+
/** File length in characters. */
|
|
1604
|
+
chars: number;
|
|
1605
|
+
}
|
|
1606
|
+
interface AiDocsIndexInput {
|
|
1607
|
+
baseId: string;
|
|
1608
|
+
/** Roots that were found, in configured order, each with its label. */
|
|
1609
|
+
roots: Array<{
|
|
1610
|
+
label: string;
|
|
1611
|
+
}>;
|
|
1612
|
+
/** The base's `homeFile` override, a rel path (applied under every root). */
|
|
1613
|
+
homeFile?: string;
|
|
1614
|
+
pages: readonly AiDocsPageInput[];
|
|
1615
|
+
/** The file cap cut the walk short (the builder also sets it past `DOCS_MAX_FILES`). */
|
|
1616
|
+
truncated?: boolean;
|
|
1617
|
+
oversizeSkipped?: number;
|
|
1618
|
+
/** Unix milliseconds; the builder is pure, so the host supplies the clock. */
|
|
1619
|
+
builtAt?: number;
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Build a base's index from host-extracted pages: ids, unique slugs, titles,
|
|
1623
|
+
* deduped and sorted pages (a page with an unknown root label or an unsafe rel
|
|
1624
|
+
* path is dropped; for a repeated id the first in sorted order wins), the file
|
|
1625
|
+
* cap, and each root's home.
|
|
1626
|
+
*/
|
|
1627
|
+
declare function buildDocsIndex(input: AiDocsIndexInput): AiDocsIndex;
|
|
1628
|
+
/** Pages by id, for the lookups the loop and the link resolver do. */
|
|
1629
|
+
declare function docsPagesById(index: Pick<AiDocsIndex, 'pages'>): Map<string, AiDocsPage>;
|
|
1630
|
+
|
|
1631
|
+
/**
|
|
1632
|
+
* Split a markdown file into the sections the index names. Pure.
|
|
1633
|
+
*
|
|
1634
|
+
* THE SECTION CONTRACT (hosts port this for `readSections` and the keyword
|
|
1635
|
+
* scan; `test/ai-fixtures/docs/sections.json` holds the cases).
|
|
1636
|
+
* - Headings are the ones `headingsOutline` reports: ATX (`#` to `######`,
|
|
1637
|
+
* up to three spaces of indent), outside frontmatter and fenced code,
|
|
1638
|
+
* with non-empty text.
|
|
1639
|
+
* - A heading's section runs from its line to the line before the NEXT
|
|
1640
|
+
* heading of any level (sections do not overlap, so a budget never counts
|
|
1641
|
+
* text twice). The last one runs to the end of the file.
|
|
1642
|
+
* - Text before the first heading is the preamble, section 0, with no
|
|
1643
|
+
* heading. It includes the frontmatter. It exists only when there is
|
|
1644
|
+
* non-whitespace text between the frontmatter and the first heading (or
|
|
1645
|
+
* the file has no heading at all and is not blank). A file that opens
|
|
1646
|
+
* with a heading has no preamble, and its frontmatter belongs to no
|
|
1647
|
+
* section (it is still in a whole-page read).
|
|
1648
|
+
* - Only the first 1000 headings (`DOCS_MAX_HEADINGS_PER_PAGE`) open a section;
|
|
1649
|
+
* a heading after that is ordinary text of the 1000th section. A heading's
|
|
1650
|
+
* text is cut to its first 200 code points (`clipDocsHeading`) before its
|
|
1651
|
+
* slug is made, as in the index.
|
|
1652
|
+
* - A section's id is `<page id>#<slug>` (slugs: `docsSlugs`); the preamble
|
|
1653
|
+
* and a whole-page read are the bare page id.
|
|
1654
|
+
*/
|
|
1655
|
+
interface DocsMarkdownSection {
|
|
1656
|
+
/** Position in the file; the preamble, when there is one, is 0. */
|
|
1657
|
+
index: number;
|
|
1658
|
+
/** Null for the preamble. */
|
|
1659
|
+
heading: {
|
|
1660
|
+
level: number;
|
|
1661
|
+
text: string;
|
|
1662
|
+
slug: string;
|
|
1663
|
+
} | null;
|
|
1664
|
+
/** Offset of the section's first character, and one past its last. */
|
|
1665
|
+
start: number;
|
|
1666
|
+
end: number;
|
|
1667
|
+
/** The section's markdown (`slice(start, end)`). */
|
|
1668
|
+
text: string;
|
|
1669
|
+
}
|
|
1670
|
+
declare function splitDocsSections(markdown: string): DocsMarkdownSection[];
|
|
1671
|
+
|
|
1672
|
+
/**
|
|
1673
|
+
* Home document per root (decision 3) and the in-memory map used when a root
|
|
1674
|
+
* has none. Pure.
|
|
1675
|
+
*
|
|
1676
|
+
* Precedence, per root: the base's override file (`homeFile`, a rel path),
|
|
1677
|
+
* then `INDEX.md`, then `README.md` at the root's top level, then the map.
|
|
1678
|
+
* Names match with ASCII case folding (`readme.md` counts); when several
|
|
1679
|
+
* pages fold to the same name the exact-case one wins, then the first in
|
|
1680
|
+
* sorted order.
|
|
1681
|
+
*/
|
|
1682
|
+
|
|
1683
|
+
/** The health text for a root with no home document. */
|
|
1684
|
+
declare const DOCS_NO_HOME_TEXT = "No home document";
|
|
1685
|
+
/** Pick the home of each root. `pages` must be the index's (sorted) pages. */
|
|
1686
|
+
declare function chooseDocsHomes(rootLabels: readonly string[], pages: readonly AiDocsPage[], homeFile?: string): AiDocsHome[];
|
|
1687
|
+
/** True when no root of the index has a real home. */
|
|
1688
|
+
declare function docsHasNoHome(homes: readonly AiDocsHome[]): boolean;
|
|
1689
|
+
/** The health line for one root's home: `null` when it has one, else "No home document". */
|
|
1690
|
+
declare function docsHomeHealth(home: AiDocsHome): string | null;
|
|
1691
|
+
interface DocsMapEntry {
|
|
1692
|
+
pageId: string;
|
|
1693
|
+
title: string;
|
|
1694
|
+
/** Texts of the page's level 1 to 3 headings, at most `DOCS_MAP_HEADINGS_PER_PAGE`. */
|
|
1695
|
+
headings: string[];
|
|
1696
|
+
}
|
|
1697
|
+
interface DocsMap {
|
|
1698
|
+
root: string;
|
|
1699
|
+
entries: DocsMapEntry[];
|
|
1700
|
+
/** Pages of the root that did not fit the cap. */
|
|
1701
|
+
omitted: number;
|
|
1702
|
+
}
|
|
1703
|
+
declare const DOCS_MAP_HEADINGS_PER_PAGE = 8;
|
|
1704
|
+
/**
|
|
1705
|
+
* The in-memory map of one root: titles and headings of its pages, at most
|
|
1706
|
+
* `cap` pages (400). When the root has more, the shallowest pages are kept
|
|
1707
|
+
* (fewest folders, then path order) and the entries are listed in path order.
|
|
1708
|
+
* Nothing is written to disk.
|
|
1709
|
+
*/
|
|
1710
|
+
declare function buildDocsMap(index: Pick<AiDocsIndex, 'pages'>, root: string, cap?: number): DocsMap;
|
|
1711
|
+
/** One line per page: `- <page id> | <title> | <heading>; <heading>`; a final line counts what was left out. */
|
|
1712
|
+
declare function renderDocsMap(map: DocsMap): string;
|
|
1713
|
+
|
|
1714
|
+
/**
|
|
1715
|
+
* Resolve the links of a base's pages inside its index (decision 14), mark the
|
|
1716
|
+
* broken ones and produce the hop-1 link list. Pure; the host only extracts
|
|
1717
|
+
* links as written (`AiDocsLink`).
|
|
1718
|
+
*
|
|
1719
|
+
* Rules.
|
|
1720
|
+
* - A link with a scheme (`https:`, `mailto:`, anything `name:` with two or
|
|
1721
|
+
* more letters before the colon) or starting `//` is `external`: not
|
|
1722
|
+
* followable, not counted as broken.
|
|
1723
|
+
* - A relative link resolves from the linking page's folder. `?query` is
|
|
1724
|
+
* dropped, `%XX` decoded (kept raw when malformed), `.` and `..`
|
|
1725
|
+
* normalised. A link that climbs above its own root, or starts with `/`
|
|
1726
|
+
* or a drive letter, is broken (`outside-root`) and never followable.
|
|
1727
|
+
* The index does not know where roots sit on disk, so a link into a
|
|
1728
|
+
* sibling root is broken too, even when that folder is another root of the
|
|
1729
|
+
* base.
|
|
1730
|
+
* - The target must be a page of the index (exact id; if the path has no
|
|
1731
|
+
* `.md` / `.markdown` extension, `.md` is tried). Else broken `not-found`.
|
|
1732
|
+
* - `#fragment` is matched against the page's heading slugs, then GitHub's
|
|
1733
|
+
* anchors. A fragment that matches nothing still resolves to the page
|
|
1734
|
+
* (`fragmentMissing`): the page is real.
|
|
1735
|
+
* - Wikilinks (`[[Name]]`, `[[Name#Heading]]`, `[[folder/Name|alias]]`)
|
|
1736
|
+
* match pages by file stem, ASCII case-folded, anywhere in the base. With
|
|
1737
|
+
* several matches the nearest to the linking page wins (same folder, then
|
|
1738
|
+
* fewest folder hops, then the shorter id, then code point order) and
|
|
1739
|
+
* `ambiguous` carries the count. This is `pickBestWikilinkTarget`
|
|
1740
|
+
* (`src/wikilinkResolve.ts`) reimplemented over page ids: core cannot
|
|
1741
|
+
* import from `src/` and the original uses Node's `path`. Matching other
|
|
1742
|
+
* active bases is the loop's job; `candidates` says how many matched here.
|
|
1743
|
+
*/
|
|
1744
|
+
|
|
1745
|
+
type AiDocsLinkStatus = 'ok' | 'broken' | 'external';
|
|
1746
|
+
type AiDocsBrokenReason = 'outside-root' | 'not-found';
|
|
1747
|
+
interface AiDocsResolvedLink {
|
|
1748
|
+
text: string;
|
|
1749
|
+
target: string;
|
|
1750
|
+
kind: AiDocsLink['kind'];
|
|
1751
|
+
status: AiDocsLinkStatus;
|
|
1752
|
+
reason?: AiDocsBrokenReason;
|
|
1753
|
+
/** The page the link lands on (status `ok`). */
|
|
1754
|
+
pageId?: string;
|
|
1755
|
+
/** The section it lands on, when the fragment matched a heading. */
|
|
1756
|
+
sectionId?: string;
|
|
1757
|
+
/** The page is real but the `#fragment` matched no heading. */
|
|
1758
|
+
fragmentMissing?: boolean;
|
|
1759
|
+
/** Wikilink only: how many pages matched the name in this base. */
|
|
1760
|
+
candidates?: number;
|
|
1761
|
+
}
|
|
1762
|
+
interface DocsLinkResolver {
|
|
1763
|
+
resolve(fromPageId: string, link: AiDocsLink): AiDocsResolvedLink;
|
|
1764
|
+
/**
|
|
1765
|
+
* Links that are `broken`, over every page of the index. The work on
|
|
1766
|
+
* wikilinks is bounded (`DOCS_MAX_LINK_WORK` candidate pages); past it the
|
|
1767
|
+
* count stops, so it is a lower bound for a hostile base.
|
|
1768
|
+
*/
|
|
1769
|
+
countBroken(): number;
|
|
1770
|
+
/** Broken links on one page, for a host that counts a page at a time and yields between pages. Shares the work bound. */
|
|
1771
|
+
countBrokenOn(pageId: string): number;
|
|
1772
|
+
/** The wikilink work bound was hit, so `countBroken` is a lower bound. */
|
|
1773
|
+
workExceeded(): boolean;
|
|
1774
|
+
}
|
|
1775
|
+
/** Order wikilink candidates nearest first (see the header). Pure and total. */
|
|
1776
|
+
declare function rankDocsWikilinkCandidates(fromPageId: string, candidateIds: readonly string[]): string[];
|
|
1777
|
+
declare function createDocsLinkResolver(index: Pick<AiDocsIndex, 'pages'>): DocsLinkResolver;
|
|
1778
|
+
interface DocsLinkList {
|
|
1779
|
+
/** Followable links, in page order, one per landing (page or section). */
|
|
1780
|
+
links: AiDocsResolvedLink[];
|
|
1781
|
+
/** Followable links beyond the cap. */
|
|
1782
|
+
omitted: number;
|
|
1783
|
+
/** Links on the page that are broken (not listed). */
|
|
1784
|
+
broken: number;
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* The hop-1 link list of a page (usually a home): its followable links,
|
|
1788
|
+
* deduplicated by landing, at most `cap` (200). Broken and external links are
|
|
1789
|
+
* left out; broken ones are counted.
|
|
1790
|
+
*/
|
|
1791
|
+
declare function docsLinkList(index: Pick<AiDocsIndex, 'pages'>, pageId: string, cap?: number, resolver?: DocsLinkResolver): DocsLinkList;
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* Keyword fallback ranking (decision 11): when a root's home is the map, or
|
|
1795
|
+
* navigation read nothing, hosts scan their files and rank sections with this,
|
|
1796
|
+
* so both hosts return the same order for the same input. Pure.
|
|
1797
|
+
*
|
|
1798
|
+
* THE RANKING CONTRACT (A10; `test/ai-fixtures/docs/keyword.json`). All
|
|
1799
|
+
* arithmetic is integer, all comparison is by code point; nothing depends on
|
|
1800
|
+
* locale.
|
|
1801
|
+
*
|
|
1802
|
+
* Case folding. ASCII `A-Z` become `a-z`; every other code point is left
|
|
1803
|
+
* unchanged (`foldAscii`). `É` does not match `é`.
|
|
1804
|
+
*
|
|
1805
|
+
* Terms. Fold the query, then split it into tokens: a token is a maximal run
|
|
1806
|
+
* of ASCII letters and digits, `_`, and any non-ASCII code point that is not
|
|
1807
|
+
* in the fixed whitespace list (`isDocsSpace`). Everything else separates
|
|
1808
|
+
* tokens (so `key-rotation` is `key`, `rotation`). Drop tokens in `STOP_WORDS`
|
|
1809
|
+
* unless that leaves none (then keep every token). Remove repeats (first
|
|
1810
|
+
* occurrence stays), keep the first `DOCS_KEYWORD_MAX_TERMS` (12). No terms,
|
|
1811
|
+
* no results.
|
|
1812
|
+
*
|
|
1813
|
+
* Fields of a section: its heading text (none for a preamble), its page title,
|
|
1814
|
+
* its page rel path, and its text. A term "occurs" in a field when the folded
|
|
1815
|
+
* field contains it as a substring (so `rotat` finds `rotation`); occurrences
|
|
1816
|
+
* are counted left to right without overlap.
|
|
1817
|
+
*
|
|
1818
|
+
* Score, per section, over all terms:
|
|
1819
|
+
* 10 x (terms occurring in the heading)
|
|
1820
|
+
* + 3 x (terms occurring in the page title)
|
|
1821
|
+
* + 2 x (terms occurring in the rel path)
|
|
1822
|
+
* + sum over terms of min(occurrences in the text, 5)
|
|
1823
|
+
* + 6 x (terms occurring in any of the four fields)
|
|
1824
|
+
* A score of 0 means no match and the section is left out.
|
|
1825
|
+
*
|
|
1826
|
+
* Order. Score descending; ties broken by section id ascending by code point
|
|
1827
|
+
* (ids are unique). The first `DOCS_KEYWORD_TOP` (20) are returned.
|
|
1828
|
+
*/
|
|
1829
|
+
|
|
1830
|
+
/** Words that carry no meaning in a question. Fixed list; the same on every host. */
|
|
1831
|
+
declare const DOCS_STOP_WORDS: readonly string[];
|
|
1832
|
+
/** Fold and split a query into ranking terms (see the header). */
|
|
1833
|
+
declare function keywordTerms(query: string): string[];
|
|
1834
|
+
/** Non-overlapping occurrences of `term` in `text`, left to right. */
|
|
1835
|
+
declare function countOccurrences(text: string, term: string): number;
|
|
1836
|
+
/** A section as the host scans it. */
|
|
1837
|
+
interface DocsKeywordSection {
|
|
1838
|
+
/** `<page id>#<slug>`, or the page id for a preamble. */
|
|
1839
|
+
id: string;
|
|
1840
|
+
pageId: string;
|
|
1841
|
+
/** The page's title. */
|
|
1842
|
+
title: string;
|
|
1843
|
+
relPath: string;
|
|
1844
|
+
/** The heading text; absent for a preamble. */
|
|
1845
|
+
heading?: string;
|
|
1846
|
+
text: string;
|
|
1847
|
+
}
|
|
1848
|
+
/** Score one section against folded terms (0 is no match). */
|
|
1849
|
+
declare function scoreKeywordSection(terms: readonly string[], section: DocsKeywordSection): number;
|
|
1850
|
+
/** Rank sections for a query: scored, ordered, top `limit` (20). */
|
|
1851
|
+
declare function rankKeywordSections(query: string, sections: readonly DocsKeywordSection[], limit?: number): AiDocsSectionRef[];
|
|
1852
|
+
|
|
1853
|
+
/**
|
|
1854
|
+
* Secrets scan (S7, A6): strict patterns, run on every string that leaves the
|
|
1855
|
+
* machine for a model, on every engine. A matching section or entry is left
|
|
1856
|
+
* out and counted in the coverage note. No lookbehind (older WebKit rejects
|
|
1857
|
+
* the whole module). Pure, linear-time (each pattern is
|
|
1858
|
+
* anchored on a literal prefix and uses bounded or possessive-by-construction
|
|
1859
|
+
* runs; `test/…` runs 1 MiB adversarial inputs).
|
|
1860
|
+
*
|
|
1861
|
+
* Patterns (a match anywhere in the text):
|
|
1862
|
+
* - aws-access-key: `AKIA` or `ASIA` + 16 of `[0-9A-Z]`, not inside a longer
|
|
1863
|
+
* alphanumeric run.
|
|
1864
|
+
* - api-token: `sk-` (optionally `sk-ant-`, `sk-proj-` ...) followed by a run
|
|
1865
|
+
* of at least 20 of `[A-Za-z0-9_-]` that contains a digit, and only where
|
|
1866
|
+
* `sk-` does not continue a word, so `task-based`, `risk-free` and
|
|
1867
|
+
* `desk-mounted` never match; or Stripe style `sk_live_` / `sk_test_` /
|
|
1868
|
+
* `rk_live_` / `rk_test_` + 16 or more alphanumerics.
|
|
1869
|
+
* - private-key: any `-----BEGIN ... PRIVATE KEY-----` header (RSA, EC,
|
|
1870
|
+
* DSA, OPENSSH, ENCRYPTED, bare, `PGP PRIVATE KEY BLOCK`). The header is
|
|
1871
|
+
* enough; the body need not be present. Whitespace between the words of
|
|
1872
|
+
* the header may include a line break (a header re-wrapped by a tool).
|
|
1873
|
+
* - jwt: `eyJ...` `.` `eyJ...` `.` signature (each part base64url; header
|
|
1874
|
+
* and payload at least 8 characters after `eyJ`; the signature may be
|
|
1875
|
+
* empty, for unsecured tokens).
|
|
1876
|
+
*
|
|
1877
|
+
* A section the host cut at the byte cap (`truncated`) may have lost the end
|
|
1878
|
+
* of a key. Hosts scan the uncapped text when they can (`capSectionText`
|
|
1879
|
+
* says so); for what arrives already cut, `scanDocsSections` also applies the
|
|
1880
|
+
* tail rule (`findSecretAtCutoff`): a key that starts in the last stretch of
|
|
1881
|
+
* the text and runs to its end counts.
|
|
1882
|
+
*/
|
|
1883
|
+
|
|
1884
|
+
type DocsSecretKind = 'aws-access-key' | 'api-token' | 'private-key' | 'jwt';
|
|
1885
|
+
/** What kind of secret `text` contains, or null. The string-level check (A6). */
|
|
1886
|
+
declare function findSecret(text: string): DocsSecretKind | null;
|
|
1887
|
+
declare function containsSecret(text: string): boolean;
|
|
1888
|
+
/**
|
|
1889
|
+
* For text that was cut at the cap: a secret that begins near the end and runs
|
|
1890
|
+
* off it (half a key is still a key). Looks only at the last 256 characters.
|
|
1891
|
+
*/
|
|
1892
|
+
declare function findSecretAtCutoff(text: string): DocsSecretKind | null;
|
|
1893
|
+
interface SecretScan<T> {
|
|
1894
|
+
/** Items with no secret, in the order given. */
|
|
1895
|
+
kept: T[];
|
|
1896
|
+
/** Ids of the items left out. Ids only: never the text (S13). */
|
|
1897
|
+
leftOut: string[];
|
|
1898
|
+
/** Why each was left out, by id. */
|
|
1899
|
+
kinds: Record<string, DocsSecretKind>;
|
|
1900
|
+
}
|
|
1901
|
+
/** Scan any list of items. `textOf` returns every string of the item that would be sent. */
|
|
1902
|
+
declare function scanForSecrets<T extends {
|
|
1903
|
+
id: string;
|
|
1904
|
+
}>(items: readonly T[], textOf: (item: T) => string | readonly string[], truncatedOf?: (item: T) => boolean): SecretScan<T>;
|
|
1905
|
+
/** Scan the sections `readSections` returned. */
|
|
1906
|
+
declare function scanDocsSections(sections: readonly AiDocsSection[]): SecretScan<AiDocsSection>;
|
|
1907
|
+
/**
|
|
1908
|
+
* This-document scope: scan the live text per section, drop the sections that
|
|
1909
|
+
* hold a key and keep the rest, so one key does not drop the whole document.
|
|
1910
|
+
* `text` is the kept sections joined as they were (in file order).
|
|
1911
|
+
*/
|
|
1912
|
+
declare function dropSecretSections(markdown: string): {
|
|
1913
|
+
text: string;
|
|
1914
|
+
total: number;
|
|
1915
|
+
leftOut: number;
|
|
1916
|
+
};
|
|
1917
|
+
/**
|
|
1918
|
+
* The coverage phrase: "1 section left out: looks like it contains a key".
|
|
1919
|
+
* `noun` is what was left out (`section`, or `entry` for navigation lists).
|
|
1920
|
+
*/
|
|
1921
|
+
declare function secretsLeftOutPhrase(count: number, noun?: 'section' | 'entry'): string;
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* The answer call's source budget: keep whole sections in the order asked
|
|
1925
|
+
* until the share of the route's context is used, then number what was kept
|
|
1926
|
+
* and write the coverage note. Pure. Built on `documentBudget.ts`
|
|
1927
|
+
* (`CHARS_PER_TOKEN`).
|
|
1928
|
+
*
|
|
1929
|
+
* Rules.
|
|
1930
|
+
* - Sections are deduplicated by id (first stays) and taken in the order
|
|
1931
|
+
* given: the loop puts the most relevant first.
|
|
1932
|
+
* - The budget is `floor(contextTokens x sourceShare / 100 x
|
|
1933
|
+
* CHARS_PER_TOKEN)` characters. A section that fits the room left is kept;
|
|
1934
|
+
* one that does not is left out and the next is tried, so a huge section
|
|
1935
|
+
* cannot starve smaller ones.
|
|
1936
|
+
* - If nothing fits whole, the first section is kept cut to the budget (on a
|
|
1937
|
+
* code point boundary, `truncated` set), so an answer always has something.
|
|
1938
|
+
* - NUMBERING HAPPENS AFTER THE CUT: `n` runs 1..k over the sections that
|
|
1939
|
+
* are actually sent, in the order kept. A model never sees a gap.
|
|
1940
|
+
* - Callers scan for secrets first (`scanDocsSections`) and pass how many
|
|
1941
|
+
* sections that left out, so the note can say so.
|
|
1942
|
+
*/
|
|
1943
|
+
|
|
1944
|
+
interface DocsBudgetOptions {
|
|
1945
|
+
/** The route's context window, in tokens. */
|
|
1946
|
+
contextTokens: number;
|
|
1947
|
+
/** Percent of it the sections may take. Clamped 30 to 80 (default 60). */
|
|
1948
|
+
sourceShare?: number;
|
|
1949
|
+
/** Sections the secrets scan already left out. */
|
|
1950
|
+
secretsLeftOut?: number;
|
|
1951
|
+
}
|
|
1952
|
+
interface AiDocsNumberedSection {
|
|
1953
|
+
/** 1-based, contiguous over what is sent. */
|
|
1954
|
+
n: number;
|
|
1955
|
+
section: AiDocsSection;
|
|
1956
|
+
}
|
|
1957
|
+
interface DocsBudgetResult {
|
|
1958
|
+
/** What goes to the model, numbered. */
|
|
1959
|
+
sent: AiDocsNumberedSection[];
|
|
1960
|
+
/** Ids left out because they did not fit. */
|
|
1961
|
+
cutIds: string[];
|
|
1962
|
+
/** Sections asked for, after dedupe and without the secret ones. */
|
|
1963
|
+
requested: number;
|
|
1964
|
+
/** Sections sent that the host or the budget cut short. */
|
|
1965
|
+
cutShort: number;
|
|
1966
|
+
/** Characters the budget allowed. */
|
|
1967
|
+
budgetChars: number;
|
|
1968
|
+
/** "answered from 4 of 7 sections, 3 left out", or null when no section was sent or asked for. */
|
|
1969
|
+
note: string | null;
|
|
1970
|
+
}
|
|
1971
|
+
/** Characters of source text a route allows. */
|
|
1972
|
+
declare function docsBudgetChars(contextTokens: number, sourceShare?: number): number;
|
|
1973
|
+
/** The coverage note (without the secrets part when `secretsLeftOut` is 0). */
|
|
1974
|
+
declare function docsCoverageNote(total: number, used: number, cutShort: number, secretsLeftOut: number): string | null;
|
|
1975
|
+
declare function budgetDocsSections(sections: readonly AiDocsSection[], opts: DocsBudgetOptions): DocsBudgetResult;
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Citations in an answer, and what Insert at cursor does with it. Pure.
|
|
1979
|
+
*
|
|
1980
|
+
* Parsing (`parseCitations`). The model cites sources as `[n]` or `[n, m]`
|
|
1981
|
+
* (the numbers the final call gave its sections). A marker is NOT a citation
|
|
1982
|
+
* when it sits in a fenced code block or code span, is followed by `(` or `:`
|
|
1983
|
+
* (a link or a definition), follows `!` or a non-citation `]` (an image or
|
|
1984
|
+
* `[text][1]` reference). Unknown numbers are dropped from the text (and from
|
|
1985
|
+
* a list); none valid means `NO_SOURCES_CITED`.
|
|
1986
|
+
*
|
|
1987
|
+
* Insert (`prepareInsertMarkdown`, A8/S8). THE SECURITY BOUNDARY IS NOT HERE. It
|
|
1988
|
+
* is the parsed walk in `ai-insert-guard.ts`, which runs on the editor's own
|
|
1989
|
+
* parser output and enforces `InsertUrlPolicy`. A string-level pass approximates
|
|
1990
|
+
* CommonMark, and wherever it disagrees with markdown-it, markup gets through.
|
|
1991
|
+
* Treat what follows as a first pass that keeps the common cases readable (in
|
|
1992
|
+
* source mode above all), and never rely on it to stop anything.
|
|
1993
|
+
* Two steps, in this order:
|
|
1994
|
+
* 1. `sanitizeInsertMarkdown`: every link, image, reference-style link and
|
|
1995
|
+
* bare or `<...>` autolink the MODEL wrote becomes plain text unless its
|
|
1996
|
+
* URL appears verbatim in a cited section's text (and is `https:`,
|
|
1997
|
+
* `http:` or, for links, `mailto:`). A link around an image is handled
|
|
1998
|
+
* innermost first, so nesting cannot carry an image through. Raw HTML
|
|
1999
|
+
* tags are escaped. Code spans and fenced blocks are left alone.
|
|
2000
|
+
* 2. `rewriteCitationsForInsert`: each citation becomes a CommonMark
|
|
2001
|
+
* relative link to the cited file, such as
|
|
2002
|
+
* `[Key rotation](security.md#key-rotation)` (spaces and brackets in
|
|
2003
|
+
* the path percent-encoded), when the current document sits under the
|
|
2004
|
+
* same root as the source; otherwise plain `file › heading` text. The
|
|
2005
|
+
* fragment is the heading slug (`docsSlug`), which is GitHub's anchor
|
|
2006
|
+
* for ASCII headings.
|
|
2007
|
+
* Those relative links are the only links Insert adds.
|
|
2008
|
+
*/
|
|
2009
|
+
|
|
2010
|
+
declare const NO_SOURCES_CITED = "No sources cited";
|
|
2011
|
+
declare const ANSWERED_WITHOUT_SOURCES = "answered without sources";
|
|
2012
|
+
type DocsCitationPart = {
|
|
2013
|
+
type: 'text';
|
|
2014
|
+
text: string;
|
|
2015
|
+
} | {
|
|
2016
|
+
type: 'cite';
|
|
2017
|
+
ns: number[];
|
|
2018
|
+
};
|
|
2019
|
+
interface ParsedCitations {
|
|
2020
|
+
/** Valid numbers in order of first appearance. */
|
|
2021
|
+
cited: number[];
|
|
2022
|
+
/** Numbers the model wrote that match no source, in order, once each. */
|
|
2023
|
+
dropped: number[];
|
|
2024
|
+
/** The answer with unknown numbers removed. */
|
|
2025
|
+
text: string;
|
|
2026
|
+
/** The same answer cut into plain text and citation parts, for rendering `[1]` chips. */
|
|
2027
|
+
parts: DocsCitationPart[];
|
|
2028
|
+
/** True when no valid citation is left. Show `NO_SOURCES_CITED`. */
|
|
2029
|
+
noSources: boolean;
|
|
2030
|
+
}
|
|
2031
|
+
/** Find `[n]` markers and keep the valid ones. `validNs` are the numbers of the sections sent. */
|
|
2032
|
+
declare function parseCitations(answer: string, validNs: Iterable<number>): ParsedCitations;
|
|
2033
|
+
/** The slug part of a section id (`undefined` for a whole page). */
|
|
2034
|
+
declare function docsSectionSlug(section: Pick<AiDocsSection, 'id' | 'pageId'>): string | undefined;
|
|
2035
|
+
/** The chip text: `file › heading`, or the file alone for a whole page. */
|
|
2036
|
+
declare function docsCitationLabel(section: Pick<AiDocsSection, 'relPath' | 'heading'>): string;
|
|
2037
|
+
/**
|
|
2038
|
+
* Percent-encode what would end a CommonMark link destination or change what
|
|
2039
|
+
* it points at: space, `%`, `#` (a file named `a#b.md` is not `a` plus a
|
|
2040
|
+
* fragment), `?`, brackets, parentheses, angle brackets, backslash, control
|
|
2041
|
+
* characters.
|
|
2042
|
+
*/
|
|
2043
|
+
declare function encodeLinkPath(path: string): string;
|
|
2044
|
+
/** Where the document being edited sits: the label of the root that contains it and its folder relative to that root (`''` for the root itself). */
|
|
2045
|
+
interface DocsDocumentLocation {
|
|
2046
|
+
root: string;
|
|
2047
|
+
folder: string;
|
|
2048
|
+
/** The base of that root. Labels are unique per base only, so a source from another base is not linked. */
|
|
2049
|
+
baseId?: string;
|
|
2050
|
+
}
|
|
2051
|
+
/** Relative path from a folder (relative to a root) to a file (relative to the same root). */
|
|
2052
|
+
declare function relativeDocsPath(fromFolder: string, toRelPath: string): string;
|
|
2053
|
+
/**
|
|
2054
|
+
* The CommonMark relative link for one cited section, or null when the
|
|
2055
|
+
* document is not under the section's root (then the caller writes plain text).
|
|
2056
|
+
*/
|
|
2057
|
+
declare function citationLink(section: AiDocsSection, location: DocsDocumentLocation | null | undefined): string | null;
|
|
2058
|
+
/**
|
|
2059
|
+
* Replace each valid `[n]` with its link (or `file › heading` text). Unknown
|
|
2060
|
+
* numbers are removed. Run `sanitizeInsertMarkdown` first.
|
|
2061
|
+
*/
|
|
2062
|
+
declare function rewriteCitationsForInsert(answer: string, sources: ReadonlyArray<AiDocsNumberedSection & {
|
|
2063
|
+
baseId?: string;
|
|
2064
|
+
}>, location?: DocsDocumentLocation | null): string;
|
|
2065
|
+
/**
|
|
2066
|
+
* What may stay live in inserted content (S8), enforced on the parsed result by
|
|
2067
|
+
* `ai-insert-guard.ts`: citation links built from the sections sent, and URLs
|
|
2068
|
+
* that appear verbatim in a cited section.
|
|
2069
|
+
*/
|
|
2070
|
+
interface InsertUrlPolicy {
|
|
2071
|
+
/** Destinations of the citation links, as written in the markdown (before the parser normalizes them). */
|
|
2072
|
+
citationHrefs: readonly string[];
|
|
2073
|
+
citedTexts: readonly string[];
|
|
2074
|
+
}
|
|
2075
|
+
/** The verbatim half of `InsertUrlPolicy`: a link (`https:`, `http:`, `mailto:`) or image (`https:`) URL found in a cited section. */
|
|
2076
|
+
declare function insertUrlIsVerbatim(policy: InsertUrlPolicy, url: string, kind: 'link' | 'image'): boolean;
|
|
2077
|
+
interface SanitizedMarkdown {
|
|
2078
|
+
markdown: string;
|
|
2079
|
+
/** Links, autolinks and definitions turned into text. */
|
|
2080
|
+
linksRemoved: number;
|
|
2081
|
+
imagesRemoved: number;
|
|
2082
|
+
}
|
|
2083
|
+
/** See the header. `citedTexts` are the texts of the sections the answer cited. */
|
|
2084
|
+
declare function sanitizeInsertMarkdown(markdown: string, citedTexts: readonly string[]): SanitizedMarkdown;
|
|
2085
|
+
/**
|
|
2086
|
+
* The text Insert at cursor puts in the document: sanitize what the model
|
|
2087
|
+
* wrote, then turn citations into relative links (or `file › heading`). Also
|
|
2088
|
+
* returns the `policy` the caller must hand to the insert, whose parsed walk is
|
|
2089
|
+
* what actually keeps anything else out.
|
|
2090
|
+
*/
|
|
2091
|
+
declare function prepareInsertMarkdown(answer: string, sources: ReadonlyArray<AiDocsNumberedSection & {
|
|
2092
|
+
baseId?: string;
|
|
2093
|
+
}>, location?: DocsDocumentLocation | null): SanitizedMarkdown & {
|
|
2094
|
+
policy: InsertUrlPolicy;
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2097
|
+
/**
|
|
2098
|
+
* Getting from a cited section back to its file, and from the document being
|
|
2099
|
+
* edited to a base. Pure, for the chat panel and the editor's reveal.
|
|
2100
|
+
*
|
|
2101
|
+
* A chip's target comes from `host.docs.listBases()` (the root) and the section
|
|
2102
|
+
* the host read (`relPath`), never from model text. The href is a `file:` URL
|
|
2103
|
+
* because both hosts need an absolute path outside the current folder, and a
|
|
2104
|
+
* Windows path would read as a URL scheme. Hosts open it after their own checks.
|
|
2105
|
+
*
|
|
2106
|
+
* A heading is found again by M2's slug rule (`docs/index.ts`), not GitHub's:
|
|
2107
|
+
* the two differ on non-ASCII text and on some duplicates.
|
|
2108
|
+
*/
|
|
2109
|
+
|
|
2110
|
+
/** `file:` URL for `relPath` under an absolute root: POSIX, drive letter or UNC. */
|
|
2111
|
+
declare function docsFileHref(root: string, relPath: string): string;
|
|
2112
|
+
/** The absolute path a section's file has, for display. Null when its base or root is no longer configured. */
|
|
2113
|
+
declare function docsSectionFile(section: Pick<AiDocsSection, 'pageId' | 'relPath'>, baseId: string, statuses: readonly AiDocBaseStatus[]): {
|
|
2114
|
+
root: string;
|
|
2115
|
+
relPath: string;
|
|
2116
|
+
baseName: string;
|
|
2117
|
+
} | null;
|
|
2118
|
+
/**
|
|
2119
|
+
* Where a folder sits among the bases, for Insert's relative links. Null for a
|
|
2120
|
+
* folder that is not absolute (an untitled document) or under no root. A base
|
|
2121
|
+
* in `prefer` wins, so a folder under two bases links to the one the answer used.
|
|
2122
|
+
*/
|
|
2123
|
+
declare function docsDocumentLocation(folder: string | null | undefined, statuses: readonly AiDocBaseStatus[], prefer?: readonly string[]): DocsDocumentLocation | null;
|
|
2124
|
+
interface DocsHeadingHit {
|
|
2125
|
+
/** Which heading, 0-based, counting the headings `headingsOutline` reports. */
|
|
2126
|
+
index: number;
|
|
2127
|
+
/** Where its line starts in `markdown`. */
|
|
2128
|
+
offset: number;
|
|
2129
|
+
}
|
|
2130
|
+
/** The heading whose M2 slug is `slug`, or null. */
|
|
2131
|
+
declare function docsHeadingAt(markdown: string, slug: string): DocsHeadingHit | null;
|
|
2132
|
+
|
|
2133
|
+
/**
|
|
2134
|
+
* The documentation chat's turn: choose one route, navigate by outlines, read
|
|
2135
|
+
* sections, answer with citations. The security model rests here, so the rules
|
|
2136
|
+
* are stated once and enforced in code, not in a prompt.
|
|
2137
|
+
*
|
|
2138
|
+
* - One route per turn (decision 7, A4). The route is resolved once, the
|
|
2139
|
+
* per-base cloud switch is checked on it (one reached `viaFallback` too),
|
|
2140
|
+
* and only then may a consent dialog or a request happen. Every hop and the
|
|
2141
|
+
* answer carry the pin, so an engine going down mid-turn fails the turn; it
|
|
2142
|
+
* never moves pages to another engine. The next turn resolves afresh.
|
|
2143
|
+
* - Fail closed (S6). No route (a tier-1 host routes by itself) counts as not
|
|
2144
|
+
* local. `allowCloud` comes from `listBases()` for this turn, never a copy.
|
|
2145
|
+
* - The model names ids and nothing else (S1). Its reply is hostile: `read`
|
|
2146
|
+
* may be missing, not a list, full of non-strings or thousands long. Only
|
|
2147
|
+
* ids found in an active base's index reach `readSections`, and what is
|
|
2148
|
+
* passed on is the index's own string, not the model's.
|
|
2149
|
+
* - Ids are unique per base only, so a read is always `(baseId, id)`. With
|
|
2150
|
+
* more than one base the ids offered carry a `b1:` token.
|
|
2151
|
+
* - Secrets (S7, A6, A7). Every string is scanned before any message is
|
|
2152
|
+
* built: section text and labels, titles, headings, link text, keyword
|
|
2153
|
+
* labels, the question. The Activity log records messages verbatim, so what
|
|
2154
|
+
* the scan leaves out can reach neither a request nor an entry.
|
|
2155
|
+
* - Nothing from a page changes the control flow (S10). Only the model's JSON,
|
|
2156
|
+
* filtered through the index, picks what is read. The answer call's output
|
|
2157
|
+
* is never parsed for further reads, and the hop cap holds regardless.
|
|
2158
|
+
* - Read-only (S12). No writes, no shell, no URLs: the loop's only effects are
|
|
2159
|
+
* `deps` and the read calls of `host.docs`.
|
|
2160
|
+
*
|
|
2161
|
+
* Pure: `ai/` has no DOM and no network, and `ai-request.ts` sits outside it,
|
|
2162
|
+
* so the completion runner and route resolution are parameters
|
|
2163
|
+
* (`ai-docs-run.ts` is the wiring).
|
|
2164
|
+
*/
|
|
2165
|
+
|
|
2166
|
+
declare const DOCS_CHAT_FEATURE = "chat";
|
|
2167
|
+
/** The This document scope's synthetic page. */
|
|
2168
|
+
declare const DOCS_DOCUMENT_BASE_ID = "document";
|
|
2169
|
+
/**
|
|
2170
|
+
* A route held for a whole turn (A4): the pair `runAiCompletion` must use, with
|
|
2171
|
+
* no re-routing and no retry elsewhere.
|
|
2172
|
+
*/
|
|
2173
|
+
interface AiRoutePin {
|
|
2174
|
+
engineId: string;
|
|
2175
|
+
modelId: string;
|
|
2176
|
+
/** How the turn's route was reached, for the badge and the Activity entry. */
|
|
2177
|
+
viaFallback?: boolean;
|
|
2178
|
+
reason?: string;
|
|
2179
|
+
/** "Allow once" answered for this turn: it covers every call of this turn, and nothing after it. */
|
|
2180
|
+
consented?: boolean;
|
|
2181
|
+
/** The engine's locality when the turn was routed. A pinned call fails if it has changed. */
|
|
2182
|
+
isLocal?: boolean;
|
|
2183
|
+
/** The turn, on the wire with every request (`AiCompletionTurn`), so a host can hold "Allow once" for exactly this turn. */
|
|
2184
|
+
turnId?: string;
|
|
2185
|
+
}
|
|
2186
|
+
/** What a chat request's Activity entry adds to the usual fields (A7). Ids only, never text. */
|
|
2187
|
+
interface AiDocsActivityDetail {
|
|
2188
|
+
/** Which navigation step, 1-based. Absent on the answer. */
|
|
2189
|
+
hop?: number;
|
|
2190
|
+
/** Navigate: the sections this hop's reply read. Answer: the sections sent. */
|
|
2191
|
+
pages: string[];
|
|
2192
|
+
/** Ids the model named that were not used, clipped and at most `DOCS_MAX_ACTIVITY_IDS`. */
|
|
2193
|
+
droppedIds: string[];
|
|
2194
|
+
/** Everything dropped, non-strings and overflow included. */
|
|
2195
|
+
droppedCount: number;
|
|
2196
|
+
/** Sections the secrets scan left out. */
|
|
2197
|
+
leftOutIds?: string[];
|
|
2198
|
+
/** Sections that did not fit the budget. */
|
|
2199
|
+
cutIds?: string[];
|
|
2200
|
+
}
|
|
2201
|
+
interface DocsRunRequest {
|
|
2202
|
+
feature: string;
|
|
2203
|
+
task: string;
|
|
2204
|
+
sends: AiSendsScope;
|
|
2205
|
+
baseIds?: string[];
|
|
2206
|
+
messages: AiMessage[];
|
|
2207
|
+
maxTokens: number;
|
|
2208
|
+
temperature: number;
|
|
2209
|
+
format?: 'json';
|
|
2210
|
+
job: 'navigate' | 'answer';
|
|
2211
|
+
thinking?: AiThinkingLevel | null | ((kind: string) => AiThinkingLevel | null);
|
|
2212
|
+
pin?: AiRoutePin;
|
|
2213
|
+
docs: AiDocsActivityDetail;
|
|
2214
|
+
}
|
|
2215
|
+
/** The thinking state of the request, as the runner reports it. */
|
|
2216
|
+
interface DocsRunThinking {
|
|
2217
|
+
kind: string;
|
|
2218
|
+
configured: AiThinkingLevel | null;
|
|
2219
|
+
sent: AiThinkingLevel | null;
|
|
2220
|
+
auto?: boolean;
|
|
2221
|
+
}
|
|
2222
|
+
interface DocsRunOutcome {
|
|
2223
|
+
result: AiCompletionResult;
|
|
2224
|
+
route: AiRouteOk | null;
|
|
2225
|
+
viaFallback: boolean;
|
|
2226
|
+
thinking: DocsRunThinking | null;
|
|
2227
|
+
/** The Activity entry's id, for `annotate`. */
|
|
2228
|
+
requestId?: string;
|
|
2229
|
+
}
|
|
2230
|
+
interface DocsRunEvents {
|
|
2231
|
+
onRoute?(route: AiRouteOk | null, thinking: DocsRunThinking | null): void;
|
|
2232
|
+
onToken?(delta: string, text: string): void;
|
|
2233
|
+
}
|
|
2234
|
+
interface DocsRouteRequest {
|
|
2235
|
+
feature: string;
|
|
2236
|
+
task: string;
|
|
2237
|
+
sends: AiSendsScope;
|
|
2238
|
+
baseIds?: string[];
|
|
2239
|
+
/** Asked about every route considered, before any consent dialog. False stops the turn with `blocked`. */
|
|
2240
|
+
allowed(route: AiRouteOk | null): boolean;
|
|
2241
|
+
}
|
|
2242
|
+
interface DocsTurnRoute {
|
|
2243
|
+
/** `allowed` said no; nothing was asked and nothing was sent. */
|
|
2244
|
+
blocked: boolean;
|
|
2245
|
+
/** Null for a tier-1 host. */
|
|
2246
|
+
route: AiRouteOk | null;
|
|
2247
|
+
/** Null when there is no route to hold. */
|
|
2248
|
+
pin: AiRoutePin | null;
|
|
2249
|
+
}
|
|
2250
|
+
/** What the loop needs from the editor's request layer (`aiDocsLoopDeps`). */
|
|
2251
|
+
interface DocsLoopDeps {
|
|
2252
|
+
resolveRoute(req: DocsRouteRequest, signal: AbortSignal): Promise<DocsTurnRoute>;
|
|
2253
|
+
run(req: DocsRunRequest, events: DocsRunEvents, signal: AbortSignal): Promise<DocsRunOutcome>;
|
|
2254
|
+
/** The route's context window, null when unknown. */
|
|
2255
|
+
contextTokens(route: AiRouteOk | null): number | null;
|
|
2256
|
+
/** Update a request's Activity entry once the hop's reply was acted on. */
|
|
2257
|
+
annotate?(requestId: string, detail: AiDocsActivityDetail): void;
|
|
2258
|
+
/** The turn holding `pin` is over, however it ended. */
|
|
2259
|
+
endTurn?(pin: AiRoutePin): void;
|
|
2260
|
+
}
|
|
2261
|
+
/** The read side of `host.docs`; the loop never touches `saveBases` or a folder picker. */
|
|
2262
|
+
type DocsReadHost = Pick<MikeDownDocsHost, 'listBases' | 'index' | 'readSections' | 'keywordSearch'>;
|
|
2263
|
+
type DocsTurnScope = {
|
|
2264
|
+
kind: 'bases';
|
|
2265
|
+
docs: DocsReadHost;
|
|
2266
|
+
options?: Partial<AiDocsOptions>;
|
|
2267
|
+
}
|
|
2268
|
+
/** Live editor text: a single synthetic page, no host calls, task `chat`. */
|
|
2269
|
+
| {
|
|
2270
|
+
kind: 'document';
|
|
2271
|
+
text: string;
|
|
2272
|
+
title?: string;
|
|
2273
|
+
options?: Partial<AiDocsOptions>;
|
|
2274
|
+
};
|
|
2275
|
+
interface DocsTurnInput {
|
|
2276
|
+
question: string;
|
|
2277
|
+
scope: DocsTurnScope;
|
|
2278
|
+
/** The user's dial, for the answer only: navigation stays on its job default (Off). */
|
|
2279
|
+
thinking?: DocsRunRequest['thinking'];
|
|
2280
|
+
}
|
|
2281
|
+
interface DocsTurnProgress {
|
|
2282
|
+
phase: 'navigate' | 'keyword' | 'answer';
|
|
2283
|
+
/** Navigation step, 1-based. */
|
|
2284
|
+
hop?: number;
|
|
2285
|
+
maxHops: number;
|
|
2286
|
+
/** Sections read so far. */
|
|
2287
|
+
pages: number;
|
|
2288
|
+
}
|
|
2289
|
+
interface DocsTurnEvents extends DocsRunEvents {
|
|
2290
|
+
onProgress?(progress: DocsTurnProgress): void;
|
|
2291
|
+
}
|
|
2292
|
+
/** A numbered section as sent, with the base it came from: ids are unique per base only. */
|
|
2293
|
+
interface DocsSentSection extends AiDocsNumberedSection {
|
|
2294
|
+
baseId: string;
|
|
2295
|
+
}
|
|
2296
|
+
interface DocsTurnAnswer {
|
|
2297
|
+
kind: 'answered';
|
|
2298
|
+
/** The answer with unknown citation numbers removed and reasoning stripped. */
|
|
2299
|
+
answer: string;
|
|
2300
|
+
citations: ParsedCitations;
|
|
2301
|
+
sent: DocsSentSection[];
|
|
2302
|
+
/** The note under the answer: coverage, secrets left out, or "answered without sources". */
|
|
2303
|
+
coverage: string;
|
|
2304
|
+
/** Nothing was read: label the answer. */
|
|
2305
|
+
withoutSources: boolean;
|
|
2306
|
+
/** Sections were sent and the answer cites none: "No sources cited". */
|
|
2307
|
+
noSources: boolean;
|
|
2308
|
+
/** Navigation calls made (a repair turn is not a hop). */
|
|
2309
|
+
hops: number;
|
|
2310
|
+
droppedCount: number;
|
|
2311
|
+
secretsLeftOut: number;
|
|
2312
|
+
/** Nav entries the scan left out of the prompts. */
|
|
2313
|
+
entriesLeftOut: number;
|
|
2314
|
+
run: DocsRunOutcome;
|
|
2315
|
+
}
|
|
2316
|
+
type DocsTurnOutcome = DocsTurnAnswer
|
|
2317
|
+
/** S6: a cloud route (or none) and a base that may not leave the machine. Nothing was asked or sent. */
|
|
2318
|
+
| {
|
|
2319
|
+
kind: 'baseLocalOnly';
|
|
2320
|
+
bases: Array<{
|
|
2321
|
+
id: string;
|
|
2322
|
+
name: string;
|
|
2323
|
+
}>;
|
|
2324
|
+
route: AiRouteOk | null;
|
|
2325
|
+
} | {
|
|
2326
|
+
kind: 'noActiveBases';
|
|
2327
|
+
}
|
|
2328
|
+
/** The question itself looks like it holds a key. Nothing was sent. */
|
|
2329
|
+
| {
|
|
2330
|
+
kind: 'questionHasSecret';
|
|
2331
|
+
}
|
|
2332
|
+
/** Another request of this editor is in flight. */
|
|
2333
|
+
| {
|
|
2334
|
+
kind: 'busy';
|
|
2335
|
+
} | {
|
|
2336
|
+
kind: 'cancelled';
|
|
2337
|
+
} | {
|
|
2338
|
+
kind: 'error';
|
|
2339
|
+
error: AiError;
|
|
2340
|
+
};
|
|
2341
|
+
/** "Active" (A1): enabled and with a root found. Host-reported state, re-checked rather than assumed. */
|
|
2342
|
+
declare function docsActiveBases(statuses: readonly AiDocBaseStatus[]): AiDocBaseStatus[];
|
|
2343
|
+
/** S6: the active bases `route` may not carry. A null route counts as not local (fail closed). */
|
|
2344
|
+
declare function docsBlockingBases(active: readonly AiDocBaseStatus[], route: AiRouteOk | null): AiDocBaseStatus[];
|
|
2345
|
+
/**
|
|
2346
|
+
* The bases of this turn that may not go on to the answer call, by what the
|
|
2347
|
+
* host says now (F6): one that was disabled or removed mid-turn on any route,
|
|
2348
|
+
* one whose cloud switch went off on a route that is not local.
|
|
2349
|
+
*/
|
|
2350
|
+
declare function docsBasesOffMidTurn(active: readonly AiDocBaseStatus[], now: readonly AiDocBaseStatus[], route: AiRouteOk | null): Array<{
|
|
2351
|
+
id: string;
|
|
2352
|
+
name: string;
|
|
2353
|
+
}>;
|
|
2354
|
+
/**
|
|
2355
|
+
* One turn, start to finish. Never rejects: a cancelled or failed hop ends the
|
|
2356
|
+
* turn with an outcome, and what Activity recorded stays there.
|
|
2357
|
+
*/
|
|
2358
|
+
declare function runDocsTurn(deps: DocsLoopDeps, input: DocsTurnInput, events: DocsTurnEvents, signal: AbortSignal): Promise<DocsTurnOutcome>;
|
|
2359
|
+
interface DocsChat {
|
|
2360
|
+
/** A turn is in flight. */
|
|
2361
|
+
readonly busy: boolean;
|
|
2362
|
+
/** Start a turn; `{ kind: 'busy' }`, with nothing touched, while another is running. Abort `signal` to cancel the hops and the answer. */
|
|
2363
|
+
run(input: DocsTurnInput, events: DocsTurnEvents, signal: AbortSignal): Promise<DocsTurnOutcome>;
|
|
2364
|
+
}
|
|
2365
|
+
/** One per editor: one chat request in flight at a time (decision 13). */
|
|
2366
|
+
declare function createDocsChat(deps: DocsLoopDeps): DocsChat;
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* The navigation hop's prompt: outlines and links only, never a body (A5),
|
|
2370
|
+
* and the parser for what comes back. Pure.
|
|
2371
|
+
*
|
|
2372
|
+
* Everything between `<index>` and `</index>` came from someone's files, so
|
|
2373
|
+
* the prompt says it is data (S10). The loop scans every string for secrets
|
|
2374
|
+
* (S7, A6) before it gets here. Nothing in a reply is trusted: `read` is
|
|
2375
|
+
* returned as it arrived and the loop filters it through the index (S1).
|
|
2376
|
+
*/
|
|
2377
|
+
|
|
2378
|
+
/** Output budget for one hop: a short list of ids (`runAiCompletion` adds reasoning headroom when thinking is on). */
|
|
2379
|
+
declare const DOCS_NAV_MAX_TOKENS = 768;
|
|
2380
|
+
/** One thing the model can ask for. `id` null: a label over `children`. */
|
|
2381
|
+
interface DocsNavEntry {
|
|
2382
|
+
id: string | null;
|
|
2383
|
+
text: string;
|
|
2384
|
+
children?: DocsNavEntry[];
|
|
2385
|
+
}
|
|
2386
|
+
/** A page's or a root's part of the index. */
|
|
2387
|
+
interface DocsNavBlock {
|
|
2388
|
+
/** "Root docs, home page: Handbook". */
|
|
2389
|
+
label: string;
|
|
2390
|
+
outline: DocsNavEntry[];
|
|
2391
|
+
links: DocsNavEntry[];
|
|
2392
|
+
/** Entries a cap already kept out of this block. */
|
|
2393
|
+
omitted: number;
|
|
2394
|
+
}
|
|
2395
|
+
interface DocsNavigatePromptInput {
|
|
2396
|
+
question: string;
|
|
2397
|
+
blocks: readonly DocsNavBlock[];
|
|
2398
|
+
/** Offered ids already asked for, so the model moves on. */
|
|
2399
|
+
alreadyRead: readonly string[];
|
|
2400
|
+
hop: number;
|
|
2401
|
+
maxHops: number;
|
|
2402
|
+
navigateBy: AiDocsNavigateBy;
|
|
2403
|
+
/** Characters of index text allowed. */
|
|
2404
|
+
maxChars: number;
|
|
2405
|
+
}
|
|
2406
|
+
interface DocsNavigatePrompt {
|
|
2407
|
+
messages: AiMessage[];
|
|
2408
|
+
/** Ids the index text offers. Zero means there is nothing to ask for: send nothing. */
|
|
2409
|
+
offered: number;
|
|
2410
|
+
/** Entries that did not fit, or that a cap kept out. */
|
|
2411
|
+
omitted: number;
|
|
2412
|
+
}
|
|
2413
|
+
declare function docsNavigateSystemPrompt(navigateBy: AiDocsNavigateBy): string;
|
|
2414
|
+
/** One line of index text: no way to start a new line or run on. Call it after the secrets scan, never before. */
|
|
2415
|
+
declare function docsNavText(text: string, max?: number): string;
|
|
2416
|
+
declare function buildDocsNavigateMessages(input: DocsNavigatePromptInput): DocsNavigatePrompt;
|
|
2417
|
+
type DocsNavReply = {
|
|
2418
|
+
ok: true;
|
|
2419
|
+
read: unknown[];
|
|
2420
|
+
done: boolean;
|
|
2421
|
+
} | {
|
|
2422
|
+
ok: false;
|
|
2423
|
+
error: string;
|
|
2424
|
+
};
|
|
2425
|
+
/**
|
|
2426
|
+
* A navigation reply's shape, and nothing more: `read` comes back as it
|
|
2427
|
+
* arrived (ids, numbers, whatever) for the loop to filter. `done` counts only
|
|
2428
|
+
* when it is exactly `true`. A bare array is taken as `read`. Missing `read`
|
|
2429
|
+
* is fine with `done: true`; otherwise it is a parse failure and gets the one
|
|
2430
|
+
* repair turn, as does a `read` that is not an array.
|
|
2431
|
+
*/
|
|
2432
|
+
declare function parseDocsNavReply(raw: string): DocsNavReply;
|
|
2433
|
+
|
|
2434
|
+
/**
|
|
2435
|
+
* The answer call's prompt: the question, the coverage note and the numbered
|
|
2436
|
+
* sections, delimited and declared to be data. Pure. Only the sections that
|
|
2437
|
+
* passed the secrets scan and the budget ever reach this builder, so the
|
|
2438
|
+
* Activity log, which records messages verbatim, cannot see the others (A7).
|
|
2439
|
+
*
|
|
2440
|
+
* The answer is text for a person. It is never parsed for further reads.
|
|
2441
|
+
*/
|
|
2442
|
+
|
|
2443
|
+
/** The longest answer asked for; a small context gets less (`docsAnswerMaxTokens`). */
|
|
2444
|
+
declare const DOCS_ANSWER_MAX_TOKENS = 2048;
|
|
2445
|
+
interface DocsAnswerPromptInput {
|
|
2446
|
+
question: string;
|
|
2447
|
+
sent: readonly AiDocsNumberedSection[];
|
|
2448
|
+
/** "answered from 4 of 7 sections, 3 left out". Counts only, no page text. */
|
|
2449
|
+
coverage: string | null;
|
|
2450
|
+
scope: 'bases' | 'document';
|
|
2451
|
+
}
|
|
2452
|
+
declare function docsAnswerSystemPrompt(scope: DocsAnswerPromptInput['scope'], withSources: boolean): string;
|
|
2453
|
+
declare function buildDocsAnswerMessages(input: DocsAnswerPromptInput): AiMessage[];
|
|
2454
|
+
/** Answer budget: what the context has left after the prompt, within a range (`runAiCompletion` adds reasoning headroom when thinking is on). */
|
|
2455
|
+
declare function docsAnswerMaxTokens(contextTokens: number, messages: readonly AiMessage[]): number;
|
|
2456
|
+
/** The answer without reasoning blocks: what the panel streams and stores. */
|
|
2457
|
+
declare function finalizeDocsAnswer(raw: string): string;
|
|
2458
|
+
|
|
1275
2459
|
/**
|
|
1276
2460
|
* Privacy copy for cloud engines: the four lines every surface shows (the
|
|
1277
2461
|
* privacy card, the disclaimer, the consent dialogs), what each feature
|
|
@@ -1312,12 +2496,17 @@ declare function aiConsentStepNote(hostAsks: boolean): string;
|
|
|
1312
2496
|
declare const AI_SENDS_TEXT: Readonly<Record<AiSendsScope, string>>;
|
|
1313
2497
|
/** For a request whose feature is unknown. */
|
|
1314
2498
|
declare const AI_SENDS_FALLBACK = "the text you ask the AI about";
|
|
2499
|
+
/** Most base names a consent sentence lists before it says "and N more". */
|
|
2500
|
+
declare const AI_SENDS_MAX_BASE_NAMES = 5;
|
|
1315
2501
|
/**
|
|
1316
2502
|
* What a request sends, as the object of a sentence ("MikeDown sends …").
|
|
1317
2503
|
* `sends` wins (whole-document Translate runs as the `rewrite` feature);
|
|
1318
|
-
* else the feature's own scope; else a generic phrase.
|
|
2504
|
+
* else the feature's own scope; else a generic phrase. For `docsBase`,
|
|
2505
|
+
* `baseNames` (the host's names for the bases the request would read from)
|
|
2506
|
+
* are spelled out: "pages from the documentation bases you turned on:
|
|
2507
|
+
* “Handbook” and “Notes”". Without names it is the bare phrase.
|
|
1319
2508
|
*/
|
|
1320
|
-
declare function whatIsSent(feature?: string, sends?: AiSendsScope): string;
|
|
2509
|
+
declare function whatIsSent(feature?: string, sends?: AiSendsScope, baseNames?: readonly string[]): string;
|
|
1321
2510
|
/** The policy of the cloud preset on `host` (an engine's base URL host), if one matches. */
|
|
1322
2511
|
declare function aiProviderPolicyForHost(host: string | null | undefined, presets?: readonly AiEnginePreset[]): AiProviderPolicy | undefined;
|
|
1323
2512
|
/**
|
|
@@ -1347,6 +2536,8 @@ interface AiConsentTextInput {
|
|
|
1347
2536
|
host: string;
|
|
1348
2537
|
feature?: string;
|
|
1349
2538
|
sends?: AiSendsScope;
|
|
2539
|
+
/** Names of the bases a `docsBase` request reads from, as the host knows them (never from the webview). */
|
|
2540
|
+
baseNames?: readonly string[];
|
|
1350
2541
|
scopeWord: AiConsentScopeWord;
|
|
1351
2542
|
/** The provider's policy (see `aiProviderPolicyForHost`). */
|
|
1352
2543
|
policy?: AiProviderPolicy | null;
|
|
@@ -1527,5 +2718,5 @@ interface AiLocalModelChoice {
|
|
|
1527
2718
|
*/
|
|
1528
2719
|
declare function localDefaultModel(models: readonly AiLocalModelChoice[]): string | null;
|
|
1529
2720
|
|
|
1530
|
-
export { AI_AUDIENCES, AI_CHARS_PER_TOKEN, AI_CLOUD_PRIVACY, AI_ENGINE_PRESETS, AI_ERROR_COPY, AI_FEATURES, AI_HOST_PRESET_FAMILY, AI_HOST_PRIVACY, AI_LOCAL_DETECT_TIMEOUT_MS, AI_LOCAL_MIN_MEMORY_GB, AI_LOCAL_MIN_UNIFIED_GB, AI_LOCAL_MIN_VRAM_GB, AI_LOCAL_ROUGH_GUESS, AI_LOCAL_SMALL_MACHINE, AI_NO_CONSENTS_TEXT, AI_PRESET_FAMILIES, AI_REWRITE_VARIANTS, AI_SENDS_FALLBACK, AI_SENDS_TEXT, AI_TASKS, ANTHROPIC_API_VERSION, ANTHROPIC_DEFAULT_MAX_TOKENS, ANTHROPIC_MODEL_TABLE, AiApiKeyFile, AiCapabilityFlag, AiCompletionRequest, AiCompletionResult, AiConsentRecord, AiDiscoveredModel, AiEngineConfig, AiEngineKind, AiEngineStatus, AiError, AiErrorCode, AiFeatureSettings, AiFinishReason, AiHardwareInfo, AiHostEngineProbe, AiLocalServerProbe, AiLocality, AiMessage, AiModelCapabilities, AiModelConfig, AiSendsScope, AiSettings, AiUsage, CHARS_PER_TOKEN, DEFAULT_LOCAL_NETWORKS, EXPLAIN_MAX_TOKENS, EXPLAIN_SYSTEM_ADDENDUM, EXPLAIN_SYSTEM_PROMPT, JSON_ONLY_INSTRUCTION, JSON_SHAPE_HINT, MODEL_LOAD_FAILED_PHRASES, OPENAI_MODEL_TABLE, OUTLINE_SYSTEM_PROMPT, PROPERTIES_SYSTEM_PROMPT, PROPERTY_DESCRIPTION_MAX_CHARS, PROPERTY_MAX_TAGS, PROPERTY_TITLE_MAX_CHARS, PROPERTY_VOCABULARY_MAX, RETRYABLE_REQUEST_PARAMS, REWRITE_CONTEXT_CHARS, REWRITE_INSTRUCTION_MAX_CHARS, REWRITE_LANGUAGE_MAX_CHARS, REWRITE_SYSTEM_PROMPT, STREAM_USAGE_HOSTS, SUMMARIZE_MIN_CONTEXT_TOKENS, SUMMARY_SHORT_DOCUMENT_CHARS, SUMMARY_SYSTEM_PROMPT, SseParser, THINKING_DEFAULT_HEADROOM_TOKENS, THINKING_HEADROOM_TOKENS, THINKING_MAX_TOKENS_CAP, TITLE_MAX_CHARS, TITLE_OUTLINE_MAX_ITEMS, TITLE_SYSTEM_PROMPT, TRANSLATE_DOCUMENT_NOTE, TRANSLATE_SYSTEM_ADDENDUM, aiConsentHost, aiConsentStepNote, aiConsentSummary, aiConsentText, aiErrorCodeFromHttp, aiErrorCopy, aiLengthLimitCopy, aiProviderPolicy, aiProviderPolicyForHost, aiResultStats, aiResultStatsText, aiResultStatsTitle, aiTimingLogParts, anthropicNextPage, base64ToBytes, budgetDocument, buildAuthHeaders, buildCompletionBody, buildEmbeddingsBody, buildExplainMessages, buildPropertiesMessages, buildRewriteMessages, buildSummaryMessages, buildTitleMessages, bytesToBase64, checkMarkdownStructure, combineRequirements, completeCapabilities, countDetectedModels, countMarkdownStructure, coveragePercent, createAnthropicStreamReader, createCompletionStreamReader, createOpenAiStreamReader, defaultAiSettings, describeHardware, detectCapabilities, detectLocality, engineEndpoints, engineLocality, escapeClosingTag, existingTagsOf, explainMaxTokens, finalizeRewriteText, finalizeSummary, formatAiSeconds, formatAiTokensPerSecond, formatMemoryGb, formatModelSize, fromWireCompletionRequest, getAiAudience, getAiFeature, getAiRewriteVariant, getAiTask, headingsOutline, hostOfUrl, isAiError, isAiErrorCode, isLocalCapable, isOpenAiReasoningModel, isRouteUsable, jsonRepairMessages, localDefaultModel, localDetectCandidates, localDetectTarget, localDetectUrl, localSizeHint, localityMismatch, makeAiError, mergeDiscoveredModels, mergeRequestOverrides, missingCapabilities, modelActiveParamsBillions, modelMemoryBytes, modelMoeFastHint, modelMoeHint, modelParamsBillions, modelSizeHint, modelSizeHintFromBytes, nearestThinkingLevel, normalizeRewriteLanguage, openAiOffReasoningEffort, parseAnthropicModels, parseEmbeddingsResponse, parseLenientJson, parseLmStudioModels, parseModelSizes, parseOllamaRunning, parseOllamaShow, parseOllamaTags, parseOmlxModelStatus, parseOpenAiModelList, parsePropertySuggestions, parseTitles, presetForEngine, propertiesMaxTokens, recommendSetupPath, renderHeadingOutline, resolveAiFeature, resolveRoute, resolveThinkingLevel, rewriteInstruction, rewriteMaxTokens, rewriteSystemPrompt, rewriteVisibleText, streamUsageSupported, summaryMaxTokens, summaryPreviewText, summaryVisibleText, taskThinkingDefault, thinkingChoices, thinkingLevelFrom, thinkingMaxTokens, thinkingOverrides, titleMaxTokens, toAiError, toWireCompletionRequest, trimRewriteContext, unsupportedRequestParam, vscodeLmAvailability, whatIsSent, withModelSizes, withModelStatus, withStreamUsage, withThinkingLevel, withoutRequestParam };
|
|
1531
|
-
export type { AiAudience, AiAudienceDefinition, AiCapabilityRequirements, AiConsentScopeWord, AiConsentState, AiConsentText, AiConsentTextInput, AiEngineEndpoints, AiEnginePreset, AiErrorCopy, AiFeatureDefinition, AiFrontmatterEntry, AiLocalDetectTarget, AiLocalModelChoice, AiModelSizeTag, AiPopularRule, AiPresetFamily, AiPresetFamilyInfo, AiProviderPolicy, AiResultStats, AiRewriteGroup, AiRewriteOutput, AiRewriteParams, AiRewriteScope, AiRewriteVariant, AiRewriteVariantDefinition, AiRouteOk, AiRouteResolution, AiRouteUnusable, AiSetupInput, AiSetupPath, AiSetupRecommendation, AiSummaryKind, AiTaskDefinition, AiThinkingChoice, AiThinkingJob, AiThinkingLevel, AiThinkingOptions, AiUnusableCode, AiWireCompletionRequest, AiWireMessage, AiWireMessagePart, BudgetedDocument, BuildCompletionOptions, CompletionStreamReader, DetectedCapabilities, DocumentBudgetOptions, ExplainPromptInput, HeadingOutlineEntry, LenientJsonResult, ParsedPropertySuggestions, ParsedTitles, PropertiesPromptInput, PropertySuggestions, ResolveRouteOptions, ResolvedAiFeature, ResolvedThinkingLevel, RewritePromptInput, SseEvent, StreamOutcome, StructureCounts, StructureDiff, StructureMismatch, SuggestedTag, SummaryPromptInput, ThinkingBudgetOptions, TitlePromptInput };
|
|
2721
|
+
export { AI_AUDIENCES, AI_CHARS_PER_TOKEN, AI_CLOUD_PRIVACY, AI_ENGINE_PRESETS, AI_ERROR_COPY, AI_FEATURES, AI_HOST_PRESET_FAMILY, AI_HOST_PRIVACY, AI_LOCAL_DETECT_TIMEOUT_MS, AI_LOCAL_MIN_MEMORY_GB, AI_LOCAL_MIN_UNIFIED_GB, AI_LOCAL_MIN_VRAM_GB, AI_LOCAL_ROUGH_GUESS, AI_LOCAL_SMALL_MACHINE, AI_NO_CONSENTS_TEXT, AI_PRESET_FAMILIES, AI_REWRITE_VARIANTS, AI_SENDS_FALLBACK, AI_SENDS_MAX_BASE_NAMES, AI_SENDS_TEXT, AI_TASKS, ANSWERED_WITHOUT_SOURCES, ANTHROPIC_API_VERSION, ANTHROPIC_DEFAULT_MAX_TOKENS, ANTHROPIC_MODEL_TABLE, AiApiKeyFile, AiCapabilityFlag, AiCompletionRequest, AiCompletionResult, AiConsentRecord, AiDiscoveredModel, AiDocBaseStatus, AiDocsHome, AiDocsIndex, AiDocsLink, AiDocsNavigateBy, AiDocsOptions, AiDocsPage, AiDocsSection, AiDocsSectionRef, AiEngineConfig, AiEngineKind, AiEngineStatus, AiError, AiErrorCode, AiFeatureSettings, AiFinishReason, AiHardwareInfo, AiHostEngineProbe, AiLocalServerProbe, AiLocality, AiMessage, AiModelCapabilities, AiModelConfig, AiSendsScope, AiSettings, AiUsage, CHARS_PER_TOKEN, CONTINUE_DEFAULT_MAX_TOKENS, CONTINUE_MAX_MAX_TOKENS, CONTINUE_MIN_MAX_TOKENS, CONTINUE_SYSTEM_PROMPT, DEFAULT_LOCAL_NETWORKS, DOCS_ANSWER_MAX_TOKENS, DOCS_BUILD_BUDGET_MS, DOCS_CHAT_FEATURE, DOCS_DOCUMENT_BASE_ID, DOCS_KEYWORD_MAX_TERMS, DOCS_KEYWORD_TOP, DOCS_LINK_SCAN_UNITS, DOCS_LINK_TEXT_UNITS, DOCS_MAP_HEADINGS_PER_PAGE, DOCS_MAX_ACTIVITY_IDS, DOCS_MAX_ACTIVITY_ID_CHARS, DOCS_MAX_DIRS, DOCS_MAX_FILES, DOCS_MAX_FILE_BYTES, DOCS_MAX_HEADINGS_PER_PAGE, DOCS_MAX_HEADING_CHARS, DOCS_MAX_ID_CHARS, DOCS_MAX_LINKS, DOCS_MAX_LINKS_PER_PAGE, DOCS_MAX_LINK_TARGET_CHARS, DOCS_MAX_LINK_WORK, DOCS_MAX_MAP_ENTRIES, DOCS_MAX_NAV_CHARS, DOCS_MAX_READ_IDS_PER_HOP, DOCS_MAX_SECTION_BYTES, DOCS_NAV_MAX_TOKENS, DOCS_NO_HOME_TEXT, DOCS_STOP_WORDS, EXPLAIN_MAX_TOKENS, EXPLAIN_SYSTEM_ADDENDUM, EXPLAIN_SYSTEM_PROMPT, GHOST_AFTER_CHARS, GHOST_BEFORE_CHARS, GHOST_DEFAULT_CONTEXT_TOKENS, GHOST_OUTLINE_MAX_CHARS, GHOST_OUTLINE_MAX_ITEMS, GHOST_REPEAT_CHARS, GHOST_RESERVE_TOKENS, GHOST_SENTENCE_CUT_CHARS, JSON_ONLY_INSTRUCTION, JSON_SHAPE_HINT, MODEL_LOAD_FAILED_PHRASES, MikeDownDocsHost, NO_SOURCES_CITED, OPENAI_MODEL_TABLE, OUTLINE_SYSTEM_PROMPT, PROPERTIES_SYSTEM_PROMPT, PROPERTY_DESCRIPTION_MAX_CHARS, PROPERTY_MAX_TAGS, PROPERTY_TITLE_MAX_CHARS, PROPERTY_VOCABULARY_MAX, RETRYABLE_REQUEST_PARAMS, REWRITE_CONTEXT_CHARS, REWRITE_INSTRUCTION_MAX_CHARS, REWRITE_LANGUAGE_MAX_CHARS, REWRITE_SYSTEM_PROMPT, STREAM_USAGE_HOSTS, SUMMARIZE_MIN_CONTEXT_TOKENS, SUMMARY_SHORT_DOCUMENT_CHARS, SUMMARY_SYSTEM_PROMPT, SseParser, THINKING_DEFAULT_HEADROOM_TOKENS, THINKING_HEADROOM_TOKENS, THINKING_MAX_TOKENS_CAP, TITLE_MAX_CHARS, TITLE_OUTLINE_MAX_ITEMS, TITLE_SYSTEM_PROMPT, TRANSLATE_DOCUMENT_NOTE, TRANSLATE_SYSTEM_ADDENDUM, aiConsentHost, aiConsentStepNote, aiConsentSummary, aiConsentText, aiErrorCodeFromHttp, aiErrorCopy, aiLengthLimitCopy, aiProviderPolicy, aiProviderPolicyForHost, aiResultStats, aiResultStatsText, aiResultStatsTitle, aiTimingLogParts, anthropicNextPage, base64ToBytes, budgetDocsSections, budgetDocument, buildAuthHeaders, buildCompletionBody, buildContinueMessages, buildDocsAnswerMessages, buildDocsIndex, buildDocsMap, buildDocsNavigateMessages, buildEmbeddingsBody, buildExplainMessages, buildPropertiesMessages, buildRewriteMessages, buildSummaryMessages, buildTitleMessages, bytesToBase64, capSectionText, checkMarkdownStructure, chooseDocsHomes, citationLink, clampDocsHops, clampDocsSourceShare, clipCodePoints, clipDocsHeading, cmpCodePoints, combineRequirements, completeCapabilities, containsSecret, continueMaxTokens, countDetectedModels, countMarkdownStructure, countOccurrences, coveragePercent, createAnthropicStreamReader, createCompletionStreamReader, createDocsChat, createDocsLinkResolver, createOpenAiStreamReader, defaultAiDocsOptions, defaultAiSettings, describeHardware, detectCapabilities, detectLocality, docsActiveBases, docsAnswerMaxTokens, docsAnswerSystemPrompt, docsBasesOffMidTurn, docsBlockingBases, docsBudgetChars, docsCitationLabel, docsCoverageNote, docsDocumentLocation, docsFileHref, docsFileStem, docsHasNoHome, docsHeadingAt, docsHomeHealth, docsIdRoot, docsLinkList, docsNavText, docsNavigateSystemPrompt, docsPageId, docsPagesById, docsRootLabels, docsSectionFile, docsSectionId, docsSectionSlug, docsSlug, docsSlugs, dropSecretSections, encodeLinkPath, engineEndpoints, engineLocality, escapeClosingTag, existingTagsOf, explainMaxTokens, finalizeDocsAnswer, finalizeRewriteText, finalizeSummary, findSecret, findSecretAtCutoff, foldAscii, formatAiSeconds, formatAiTokensPerSecond, formatMemoryGb, formatModelSize, fromWireCompletionRequest, frontmatterEndOffset, getAiAudience, getAiFeature, getAiRewriteVariant, getAiTask, ghostAcceptWord, ghostContext, ghostPrefixMatch, githubAnchors, headingsOutline, headingsWithOffsets, hostOfUrl, insertUrlIsVerbatim, isAiError, isAiErrorCode, isLocalCapable, isOpenAiReasoningModel, isRouteUsable, isSafeRelPath, jsonRepairMessages, keywordTerms, localDefaultModel, localDetectCandidates, localDetectTarget, localDetectUrl, localSizeHint, localityMismatch, makeAiError, mergeDiscoveredModels, mergeRequestOverrides, missingCapabilities, modelActiveParamsBillions, modelMemoryBytes, modelMoeFastHint, modelMoeHint, modelParamsBillions, modelSizeHint, modelSizeHintFromBytes, nearestThinkingLevel, normalizeRewriteLanguage, openAiOffReasoningEffort, parseAnthropicModels, parseCitations, parseDocsId, parseDocsNavReply, parseEmbeddingsResponse, parseLenientJson, parseLmStudioModels, parseModelSizes, parseOllamaRunning, parseOllamaShow, parseOllamaTags, parseOmlxModelStatus, parseOpenAiModelList, parsePropertySuggestions, parseTitles, prepareInsertMarkdown, presetForEngine, propertiesMaxTokens, rankDocsWikilinkCandidates, rankKeywordSections, recommendSetupPath, relativeDocsPath, renderDocsMap, renderHeadingOutline, resolveAiFeature, resolveRoute, resolveThinkingLevel, rewriteCitationsForInsert, rewriteInstruction, rewriteMaxTokens, rewriteSystemPrompt, rewriteVisibleText, runDocsTurn, sanitizeInsertMarkdown, scanDocsSections, scanForSecrets, scoreKeywordSection, secretsLeftOutPhrase, splitDocsSections, streamUsageSupported, summaryMaxTokens, summaryPreviewText, summaryVisibleText, taskThinkingDefault, thinkingChoices, thinkingLevelFrom, thinkingMaxTokens, thinkingOverrides, titleMaxTokens, toAiError, toWireCompletionRequest, trimGhostSuggestion, trimGhostSuggestionDetailed, trimRewriteContext, unsupportedRequestParam, vscodeLmAvailability, whatIsSent, withModelSizes, withModelStatus, withStreamUsage, withThinkingLevel, withoutRequestParam };
|
|
2722
|
+
export type { AiAudience, AiAudienceDefinition, AiCapabilityRequirements, AiConsentScopeWord, AiConsentState, AiConsentText, AiConsentTextInput, AiDocsActivityDetail, AiDocsBrokenReason, AiDocsIndexInput, AiDocsLinkStatus, AiDocsNumberedSection, AiDocsPageInput, AiDocsResolvedLink, AiEngineEndpoints, AiEnginePreset, AiErrorCopy, AiFeatureDefinition, AiFrontmatterEntry, AiLocalDetectTarget, AiLocalModelChoice, AiModelSizeTag, AiPopularRule, AiPresetFamily, AiPresetFamilyInfo, AiProviderPolicy, AiResultStats, AiRewriteGroup, AiRewriteOutput, AiRewriteParams, AiRewriteScope, AiRewriteVariant, AiRewriteVariantDefinition, AiRouteOk, AiRoutePin, AiRouteResolution, AiRouteUnusable, AiSetupInput, AiSetupPath, AiSetupRecommendation, AiSummaryKind, AiTaskDefinition, AiThinkingChoice, AiThinkingJob, AiThinkingLevel, AiThinkingOptions, AiUnusableCode, AiWireCompletionRequest, AiWireMessage, AiWireMessagePart, BudgetedDocument, BuildCompletionOptions, CompletionStreamReader, ContinuePromptInput, DetectedCapabilities, DocsAnswerPromptInput, DocsBudgetOptions, DocsBudgetResult, DocsChat, DocsCitationPart, DocsDocumentLocation, DocsHeadingHit, DocsKeywordSection, DocsLinkList, DocsLinkResolver, DocsLoopDeps, DocsMap, DocsMapEntry, DocsMarkdownSection, DocsNavBlock, DocsNavEntry, DocsNavReply, DocsNavigatePrompt, DocsNavigatePromptInput, DocsReadHost, DocsRouteRequest, DocsRunEvents, DocsRunOutcome, DocsRunRequest, DocsRunThinking, DocsSecretKind, DocsSentSection, DocsTurnAnswer, DocsTurnEvents, DocsTurnInput, DocsTurnOutcome, DocsTurnProgress, DocsTurnRoute, DocsTurnScope, DocumentBudgetOptions, ExplainPromptInput, GhostBlockKind, GhostContext, GhostContextOptions, GhostTrimOptions, GhostTrimResult, HeadingOutlineEntry, HeadingWithOffsets, InsertUrlPolicy, LenientJsonResult, ParsedCitations, ParsedPropertySuggestions, ParsedTitles, PropertiesPromptInput, PropertySuggestions, ResolveRouteOptions, ResolvedAiFeature, ResolvedThinkingLevel, RewritePromptInput, SanitizedMarkdown, SecretScan, SseEvent, StreamOutcome, StructureCounts, StructureDiff, StructureMismatch, SuggestedTag, SummaryPromptInput, ThinkingBudgetOptions, TitlePromptInput };
|