@cerebriline/core 4.100.244 → 4.100.246

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.
@@ -158,6 +158,11 @@ export interface CappedThinkingCondenserConfig {
158
158
  /** Absent when no provider is resolved yet; the condenser then stands down. */
159
159
  providerConfig?: ProviderConfig;
160
160
  summarizer?: CoreCompactionSummarizerConfig;
161
+ /**
162
+ * The conversation the notes are written for (`ProviderConfig.sideCallOf`).
163
+ * Set for the lead only: an agent's note must never close the lead.
164
+ */
165
+ sideCallOf?: string;
161
166
  logger?: BasicLogger;
162
167
  }
163
168
  type PrepareTurnResult = {
@@ -61,6 +61,12 @@ export interface ContextCompactionPrepareTurnOptions {
61
61
  * visibility is. See {@link createCompactionJournal}.
62
62
  */
63
63
  journal?: CompactionJournal;
64
+ /**
65
+ * The conversation the summaries are written for
66
+ * (`ProviderConfig.sideCallOf`). Set for the lead only: an agent's summary
67
+ * must never close the lead.
68
+ */
69
+ sideCallOf?: string;
64
70
  }
65
71
  /**
66
72
  * The share of the *content* a compaction aims to leave behind.
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Search of a workspace's code by meaning, as `search_codebase` uses it.
3
+ *
4
+ * The index is the user's choice per folder (Settings > Library): building it
5
+ * sends every source file in the folder to the embedding model. Where the
6
+ * folder is opted in and an embedding model is set, this is the executor a
7
+ * host hands to the tools; the index is brought up to date in the background,
8
+ * and a search made before that is done says so instead of waiting.
9
+ */
10
+ import { type LibrarySettings } from "@cerebriline/shared";
11
+ import { type CodeIndex, type CodeSearchResult } from "../../services/retrieval/code-index";
12
+ import type { RetrievalEndpoint } from "../../services/retrieval/embedding-client";
13
+ import type { SemanticSearchExecutor } from "./types";
14
+ export interface CodeSearchConfig {
15
+ settings: LibrarySettings;
16
+ /** The embedding model, when the user has set one. */
17
+ embedding?: RetrievalEndpoint;
18
+ /** The reranking model, when the user has set one. */
19
+ reranker?: RetrievalEndpoint;
20
+ }
21
+ export interface CodeIndexProgress {
22
+ /** What the refresh is doing now. */
23
+ phase: "reading" | "embedding";
24
+ done: number;
25
+ total: number;
26
+ }
27
+ export interface CodeIndexRefreshState {
28
+ running: boolean;
29
+ progress?: CodeIndexProgress;
30
+ /** Why the last refresh stopped short, when it did. */
31
+ problem?: string;
32
+ /** When the last refresh finished, in epoch milliseconds. */
33
+ finishedAt?: number;
34
+ }
35
+ export interface CreateCodeSearchOptions {
36
+ /** Read on every call: the settings can change mid-session. */
37
+ getConfig: () => CodeSearchConfig;
38
+ /** @default the shared code index of the data folder */
39
+ index?: CodeIndex;
40
+ /**
41
+ * Download LanceDB, which holds the vectors, when it is not installed. For
42
+ * a host with no panel to offer the download from. @default false
43
+ */
44
+ install?: boolean;
45
+ log?: (message: string) => void;
46
+ }
47
+ export interface CodeSearch extends SemanticSearchExecutor {
48
+ /**
49
+ * Bring a folder's index up to date: read what changed, then embed what has
50
+ * no vectors. One at a time per folder; a second call joins the first.
51
+ * Resolves when it is done and never rejects: the state says what happened.
52
+ */
53
+ refresh(root: string): Promise<void>;
54
+ state(root: string): CodeIndexRefreshState;
55
+ }
56
+ /** Whether a folder is searched by meaning: opted in, with a model to embed with. */
57
+ export declare function codeSearchAvailable(config: CodeSearchConfig, root: string): boolean;
58
+ /** The hits as the model reads them: where each passage is, then the passage. */
59
+ export declare function formatCodeHits(result: CodeSearchResult): string;
60
+ export declare function createCodeSearch(options: CreateCodeSearchOptions): CodeSearch;
61
+ /**
62
+ * The lead's code search as a delegated agent uses it.
63
+ *
64
+ * An agent is built without the lead's executors, so that none of them points
65
+ * its file tools at the real workspace. This one only reads, and what it reads
66
+ * for line numbers goes through the agent's own copy of the folder: a passage
67
+ * in a file the agent has edited is given the lines it is on there.
68
+ */
69
+ export declare function semanticSearchForAgent(lead: SemanticSearchExecutor | undefined, overlay: {
70
+ read(path: string): Promise<Buffer>;
71
+ } | undefined): SemanticSearchExecutor | undefined;
@@ -6,7 +6,7 @@
6
6
  import { type AgentTool, type ShellKind } from "@cerebriline/shared";
7
7
  import { type QaCredential } from "./qa-credentials";
8
8
  import { type ApplyPatchInput, type AskQuestionInput, type AwkToolInput, type EditFileInput, type ExtractDocumentInput, type FetchWebContentInput, type GrepToolInput, type ReadFileRequest, type ReadFilesInput, type SearchCodebaseInput, type SedToolInput, type SkillsInput, type SubmitInput } from "./schemas";
9
- import type { ApplyPatchExecutor, AskQuestionExecutor, AwkExecutor, CreateDefaultToolsOptions, DefaultToolsConfig, EditorExecutor, ExtractDocumentExecutor, FileReadExecutor, GrepExecutor, SearchExecutor, SedExecutor, ShellExecutor, SkillsExecutorWithMetadata, ToolOperationResult, VerifySubmitExecutor, WebFetchExecutor } from "./types";
9
+ import type { ApplyPatchExecutor, AskQuestionExecutor, AwkExecutor, CreateDefaultToolsOptions, DefaultToolsConfig, EditorExecutor, ExtractDocumentExecutor, FileReadExecutor, GrepExecutor, SearchExecutor, SedExecutor, SemanticSearchExecutor, ShellExecutor, SkillsExecutorWithMetadata, ToolOperationResult, VerifySubmitExecutor, WebFetchExecutor } from "./types";
10
10
  /**
11
11
  * What a successful read with no content is told to mean.
12
12
  *
@@ -41,7 +41,7 @@ export declare function createReadFilesTool(executor: FileReadExecutor, config?:
41
41
  *
42
42
  * Performs regex pattern searches across the codebase.
43
43
  */
44
- export declare function createSearchTool(executor: SearchExecutor, config?: Pick<DefaultToolsConfig, "cwd" | "searchTimeoutMs">): AgentTool<SearchCodebaseInput, ToolOperationResult[]>;
44
+ export declare function createSearchTool(executor: SearchExecutor, config?: Pick<DefaultToolsConfig, "cwd" | "searchTimeoutMs">, semantic?: SemanticSearchExecutor["search"]): AgentTool<SearchCodebaseInput, ToolOperationResult[]>;
45
45
  /**
46
46
  * Build the run_commands tool description for the shell that will actually
47
47
  * execute the commands. The shell kind decides the syntax guidance (quoting,
@@ -16,7 +16,7 @@ export { type BuiltinToolAvailabilityContext, getCoreAcpToolNames, getCoreBuilti
16
16
  export { type ApplyPatchInput, ApplyPatchInputSchema, type AskQuestionInput, AskQuestionInputSchema, AwkInputSchema, type AwkToolInput, type EditFileInput, EditFileInputSchema, type ExtractDocumentInput, ExtractDocumentInputSchema, type FetchWebContentInput, FetchWebContentInputSchema, GrepInputSchema, type GrepToolInput, type ReadFileRequest, ReadFileRequestSchema, type ReadFilesInput, ReadFilesInputSchema, type RunCommandsInput, RunCommandsInputSchema, type SearchCodebaseInput, SearchCodebaseInputSchema, SedInputSchema, type SedToolInput, type SkillsInput, SkillsInputSchema, type StructuredCommandInput, StructuredCommandInputSchema, type SubmitInput, SubmitInputSchema, type WebFetchRequest, WebFetchRequestSchema, } from "./schemas";
17
17
  export { buildTaskProgressReminder, buildTaskProgressState, DEFAULT_TASK_PROGRESS_REMINDER_INTERVAL, parseTaskProgress, readTaskProgress, TASK_PROGRESS_PARAM, TASK_PROGRESS_PARAM_DESCRIPTION, type TaskProgressItem, type TaskProgressState, TaskProgressTracker, type TaskProgressTrackerOptions, withTaskProgressCapture, withTaskProgressParam, } from "./task-progress";
18
18
  export { TEAM_TOOL_NAMES } from "./team/team-tools";
19
- export type { ApplyPatchExecutor, AskQuestionExecutor, AwkExecutor, CreateDefaultToolsOptions, DefaultToolName, DefaultToolsConfig, EditorExecutor, FileReadExecutor, GrepExecutor, SearchExecutor, SedExecutor, ShellExecutionOptions, ShellExecutor, SkillsExecutor, SkillsExecutorSkillMetadata, SkillsExecutorWithMetadata, ToolExecutors, ToolOperationResult, VerifySubmitExecutor, WebFetchExecutor, } from "./types";
19
+ export type { ApplyPatchExecutor, AskQuestionExecutor, AwkExecutor, CreateDefaultToolsOptions, DefaultToolName, DefaultToolsConfig, EditorExecutor, FileReadExecutor, GrepExecutor, SearchExecutor, SedExecutor, SemanticSearchExecutor, ShellExecutionOptions, ShellExecutor, SkillsExecutor, SkillsExecutorSkillMetadata, SkillsExecutorWithMetadata, ToolExecutors, ToolOperationResult, VerifySubmitExecutor, WebFetchExecutor, } from "./types";
20
20
  import { type AgentTool } from "@cerebriline/shared";
21
21
  import { type DefaultExecutorsOptions } from "./executors/index";
22
22
  import type { CreateDefaultToolsOptions, ToolExecutors } from "./types";
@@ -26,6 +26,20 @@ export interface LibraryScrapeConfig extends ScrapeEndpoint {
26
26
  maxPages: number;
27
27
  /** How many links deep a crawl follows. */
28
28
  maxDepth: number;
29
+ /**
30
+ * `false`: every task is offered the general `web_scrape`
31
+ * (`web-scrape-tool.ts`), which the librarian then uses too. Otherwise
32
+ * scraping is the librarian's only.
33
+ */
34
+ librarianOnly?: boolean;
35
+ /**
36
+ * What a site crawl may fetch besides its pages: how many files, how
37
+ * large one may be and how much in all, in megabytes. Absent, the
38
+ * defaults of `ScrapeSettings`.
39
+ */
40
+ maxFiles?: number;
41
+ maxFileMb?: number;
42
+ maxTotalMb?: number;
29
43
  }
30
44
  export interface LibraryToolsConfig {
31
45
  settings: LibrarySettings;
@@ -775,16 +775,7 @@ export type AskQuestionInput = z.infer<typeof AskQuestionInputSchema>;
775
775
  * Input for the submit and exit tool
776
776
  */
777
777
  export type SubmitInput = z.infer<typeof SubmitInputSchema>;
778
- /**
779
- * What `grep`, `sed` and `awk` accept, as against what they advertise.
780
- *
781
- * The advertised shape keeps `array`, because that is the shape that batches.
782
- * These wrappers only widen the door: the one field each of them gets wrong is
783
- * the file list, and it is always wrong the same way. Every other field is the
784
- * canonical schema's own, so the parsed output is the canonical type already --
785
- * no pipe back through it, which `z.coerce` fields make ill-typed anyway.
786
- */
787
- export declare const GrepInputUnionSchema: z.ZodObject<{
778
+ export declare const GrepInputUnionSchema: z.ZodPreprocess<z.ZodObject<{
788
779
  pattern: z.ZodString;
789
780
  ignore_case: z.ZodOptional<z.ZodBoolean>;
790
781
  invert: z.ZodOptional<z.ZodBoolean>;
@@ -797,7 +788,7 @@ export declare const GrepInputUnionSchema: z.ZodObject<{
797
788
  context: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
798
789
  max_count: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
799
790
  paths: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodPipe<z.ZodString, z.ZodTransform<string[], string>>]>>;
800
- }, z.core.$strip>;
791
+ }, z.core.$strip>>;
801
792
  export declare const SedInputUnionSchema: z.ZodObject<{
802
793
  script: z.ZodString;
803
794
  in_place: z.ZodOptional<z.ZodBoolean>;
@@ -51,6 +51,27 @@ export interface SearchQueryOptions {
51
51
  maxPerFile?: number;
52
52
  }
53
53
  export type SearchExecutor = (query: string, cwd: string, context: AgentToolContext, options?: SearchQueryOptions) => Promise<string>;
54
+ /**
55
+ * Search of the workspace's code by meaning, for `search_codebase`'s
56
+ * `mode: "semantic"`. A host supplies it only where the workspace is indexed:
57
+ * its presence is what adds the mode to the tool.
58
+ */
59
+ export interface SemanticSearchExecutor {
60
+ /**
61
+ * Asked once, when a session's tools are built: whether this folder is
62
+ * indexed. One host serves many workspaces, so the answer is per folder.
63
+ */
64
+ available(cwd: string): boolean;
65
+ search(query: string, cwd: string, context: AgentToolContext, options?: SemanticSearchOptions): Promise<string>;
66
+ }
67
+ export interface SemanticSearchOptions {
68
+ /**
69
+ * Read a file of the folder as the caller sees it, by absolute path. A
70
+ * delegated agent works on its own copy: the lines a passage is on are the
71
+ * lines of that copy, not of the lead's file.
72
+ */
73
+ readFile?: (absolutePath: string) => Promise<string | undefined>;
74
+ }
54
75
  /**
55
76
  * Per-call execution options for a shell executor.
56
77
  */
@@ -209,6 +230,8 @@ export interface ToolExecutors {
209
230
  readFile?: FileReadExecutor;
210
231
  /** Codebase search implementation */
211
232
  search?: SearchExecutor;
233
+ /** Code search by meaning; adds `mode: "semantic"` to search_codebase */
234
+ semanticSearch?: SemanticSearchExecutor;
212
235
  /** Shell command execution implementation */
213
236
  bash?: ShellExecutor;
214
237
  /** Web content fetching implementation */
@@ -0,0 +1,49 @@
1
+ /**
2
+ * `web_scrape`: the web through a Firecrawl endpoint.
3
+ *
4
+ * Two shapes of one tool. The librarian's looks at the web to choose what a
5
+ * book is made from: search, map, read. The general one is offered to any
6
+ * task when the user turns "Only for the librarian" off, and adds what a task
7
+ * outside the Library needs: a crawl that saves a site into the workspace.
8
+ * By default that is the site itself -- every page as it was served and as
9
+ * the browser rendered it, with the stylesheets, scripts, pictures and fonts
10
+ * it uses -- beside a markdown reading of each page; `content: "text"` keeps
11
+ * the markdown alone, for notes.
12
+ *
13
+ * The lead's only: it is not in `DELEGATED_HOST_TOOLS`, so a delegated agent,
14
+ * whose writes go through its overlay, is never handed a tool that writes to
15
+ * the workspace directly.
16
+ */
17
+ import { type AgentTool } from "@cerebriline/shared";
18
+ import type { LibraryScrapeConfig } from "./library-tools";
19
+ export { cleanLink, linkCensus, pageFileName } from "./web-site-crawl";
20
+ export declare const WEB_SCRAPE_TOOL_NAME = "web_scrape";
21
+ export declare const NO_SCRAPER = "Web scraping is not set up for this session. The user sets the endpoint under Settings > Features and allows it in the API configuration; do not call this again in this task.";
22
+ export interface WebScrapeToolOptions {
23
+ /** The folder saved pages are written under. */
24
+ cwd: string;
25
+ /** The endpoint and its limits, read on every call. Undefined: not set up. */
26
+ getScrape: () => LibraryScrapeConfig | undefined;
27
+ /** What stops the tool before the endpoint is asked, said to the model. */
28
+ unavailable?: () => string | undefined;
29
+ /** The general tool: `crawl`, and `save_to`. @default false, the librarian's */
30
+ general?: boolean;
31
+ onError?: (message: string, error: unknown) => void;
32
+ /**
33
+ * A text file the tool wrote, by absolute path. The host forgets what it
34
+ * knew of the file, so a later read is not told that something outside the
35
+ * session changed it.
36
+ */
37
+ onWrote?: (file: string) => void;
38
+ }
39
+ /** `target` under `cwd`, or nothing when it would leave the folder. */
40
+ export declare function workspacePath(cwd: string, target: string): string | undefined;
41
+ export declare function createWebScrapeTool(options: WebScrapeToolOptions): AgentTool;
42
+ /**
43
+ * The general tool, when scraping is set up, allowed, and not kept for the
44
+ * librarian. Decided at session start, like every other tool list; the
45
+ * endpoint itself is read again on every call.
46
+ */
47
+ export declare function createWebScrapeTools(options: Omit<WebScrapeToolOptions, "general"> & {
48
+ log?: (message: string) => void;
49
+ }): AgentTool[];
@@ -0,0 +1,96 @@
1
+ /**
2
+ * A site crawled into a folder of the workspace, and continued later.
3
+ *
4
+ * The folder keeps a record of the crawl (`.scrape.json`): the pages read
5
+ * and where each was saved, the files fetched, the pages that are linked and
6
+ * were not read, and the files a limit left out. A later crawl into the same
7
+ * folder with `resume` reads only what is missing -- the pages from that
8
+ * list, one by one through the endpoint, and the files not yet on disk --
9
+ * and nothing that is already there.
10
+ *
11
+ * Every limit that stopped something is said at the top of the result, as an
12
+ * alert the model is told to pass on: the user set those limits, and only
13
+ * the user can raise them.
14
+ */
15
+ import { type ScrapedPage } from "../../services/retrieval/firecrawl";
16
+ import type { LibraryScrapeConfig } from "./library-tools";
17
+ export declare function plural(count: number, one: string, many?: string): string;
18
+ /** An http(s) address without its fragment, or nothing. */
19
+ export declare function cleanLink(link: string): string | undefined;
20
+ /**
21
+ * A page's file under the crawl's folder: its host and path, with what a
22
+ * file name cannot hold replaced, so two pages of a site never collide and
23
+ * the folder reads like the site.
24
+ */
25
+ export declare function pageFileName(url: string, taken: Set<string>): string;
26
+ export declare function pageFile(page: ScrapedPage): string;
27
+ /**
28
+ * Where the links of the pages read lead: pages of the same site that were
29
+ * not read, and other sites. It is what tells "the site has no more pages"
30
+ * from "the crawl stopped short" -- the two read the same from a page count.
31
+ */
32
+ export declare function linkCensus(pages: readonly ScrapedPage[], start: string): {
33
+ unread: string[];
34
+ elsewhere: string[];
35
+ };
36
+ export declare function sitesLine(hosts: readonly string[], most?: number): string;
37
+ /** The record a crawl leaves in its folder. */
38
+ export declare const SITE_RECORD_FILE = ".scrape.json";
39
+ export interface SiteRecord {
40
+ version: 1;
41
+ /** The address the crawl started from. */
42
+ url: string;
43
+ content: "site" | "text";
44
+ wholeSite: boolean;
45
+ include: string[];
46
+ exclude: string[];
47
+ /** Pages read, by address. */
48
+ pages: Record<string, {
49
+ title?: string;
50
+ markdown: string;
51
+ characters: number;
52
+ served?: string;
53
+ rendered?: string;
54
+ }>;
55
+ /** Files fetched, by address. */
56
+ assets: Record<string, {
57
+ file: string;
58
+ bytes: number;
59
+ }>;
60
+ /** Pages of the site that are linked and were not read. */
61
+ unread: string[];
62
+ /** Files a limit left out. */
63
+ assetsLeft: string[];
64
+ /** Files that could not be fetched, with the reason. */
65
+ failed: Record<string, string>;
66
+ /** Pages that could not be read, with the reason. */
67
+ failedPages: Record<string, string>;
68
+ }
69
+ export interface CrawlToFolderRequest {
70
+ scrape: LibraryScrapeConfig;
71
+ url: string;
72
+ /** The folder, absolute. */
73
+ target: string;
74
+ /** The folder as the model named it, for the result. */
75
+ folder: string;
76
+ limit?: number;
77
+ depth?: number;
78
+ include: string[];
79
+ exclude: string[];
80
+ wholeSite?: boolean;
81
+ content?: "site" | "text";
82
+ resume: boolean;
83
+ signal?: AbortSignal;
84
+ emit?: (status: string) => void;
85
+ /** A text file the crawl wrote or rewrote, by absolute path. */
86
+ wrote?: (file: string) => void;
87
+ /** The crawl stopped at a limit of the user's; see `reportStoppedForUser`. */
88
+ stopped?: (reason: string) => void;
89
+ }
90
+ /**
91
+ * Whether a link is one this crawl reads: the same site, below the starting
92
+ * address unless the whole site was asked for, and through the path filters.
93
+ */
94
+ export declare function inCrawlScope(link: string, record: Pick<SiteRecord, "url" | "wholeSite" | "include" | "exclude">): boolean;
95
+ /** Crawl a site into a folder, or continue the crawl that is there. */
96
+ export declare function crawlToFolder(request: CrawlToFolderRequest): Promise<string>;