@ikarmic/forge-core 5.2.0 → 5.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/dist/agent/agent.js +324 -122
- package/dist/agent/cache-hints.d.ts +2 -0
- package/dist/agent/cache-hints.js +18 -3
- package/dist/agent/enhance-prompt.js +2 -1
- package/dist/agent/history-adapt.d.ts +23 -0
- package/dist/agent/history-adapt.js +114 -0
- package/dist/agent/prompts.d.ts +19 -2
- package/dist/agent/prompts.js +44 -2
- package/dist/agent/retry.d.ts +50 -0
- package/dist/agent/retry.js +192 -0
- package/dist/agent/shell-command.d.ts +23 -0
- package/dist/agent/shell-command.js +93 -0
- package/dist/agent/tool-repair.d.ts +8 -0
- package/dist/agent/tool-repair.js +16 -0
- package/dist/catalog/models-dev-snapshot.d.ts +1 -0
- package/dist/catalog/models-dev-snapshot.js +3 -0
- package/dist/catalog/models-dev.d.ts +45 -0
- package/dist/catalog/models-dev.js +155 -0
- package/dist/checkpoints/store.js +3 -1
- package/dist/context/compaction.d.ts +21 -6
- package/dist/context/compaction.js +94 -28
- package/dist/context/mask.d.ts +9 -9
- package/dist/context/mask.js +30 -1
- package/dist/format/auto-format.d.ts +22 -0
- package/dist/format/auto-format.js +39 -0
- package/dist/git/auto-commit.d.ts +4 -2
- package/dist/git/auto-commit.js +16 -5
- package/dist/github/github-tools.d.ts +1 -0
- package/dist/github/github-tools.js +9 -9
- package/dist/github/pr.d.ts +34 -0
- package/dist/github/pr.js +70 -0
- package/dist/human-text.d.ts +6 -0
- package/dist/human-text.js +37 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.js +14 -6
- package/dist/journey/answers-block.d.ts +2 -4
- package/dist/lsp/diagnostics.d.ts +4 -0
- package/dist/lsp/diagnostics.js +8 -2
- package/dist/lsp/index.d.ts +1 -1
- package/dist/lsp/index.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/json-schema-to-zod.js +2 -4
- package/dist/mcp/mcp-client.d.ts +14 -0
- package/dist/mcp/mcp-client.js +102 -18
- package/dist/memory/session-digest.js +2 -1
- package/dist/orchestrator/specialists-registry.js +14 -1
- package/dist/orchestrator/specialists.js +3 -3
- package/dist/pricing.js +12 -0
- package/dist/semantic/embedder.d.ts +11 -0
- package/dist/semantic/embedder.js +16 -0
- package/dist/semantic/semantic-index.d.ts +39 -1
- package/dist/semantic/semantic-index.js +43 -13
- package/dist/semantic/vector-store.d.ts +2 -0
- package/dist/semantic/vector-store.js +13 -1
- package/dist/sessions/index.d.ts +2 -2
- package/dist/sessions/index.js +1 -1
- package/dist/sessions/search.js +2 -2
- package/dist/sessions/session-export.d.ts +1 -1
- package/dist/sessions/session-export.js +41 -33
- package/dist/sessions/session-store.d.ts +20 -1
- package/dist/sessions/session-store.js +7 -0
- package/dist/sessions/watch.js +4 -4
- package/dist/skills/activator.d.ts +6 -0
- package/dist/skills/activator.js +17 -0
- package/dist/skills/skill-tool.d.ts +12 -0
- package/dist/skills/skill-tool.js +28 -0
- package/dist/tools/background-process.d.ts +63 -0
- package/dist/tools/background-process.js +150 -0
- package/dist/tools/command-sandbox.d.ts +24 -0
- package/dist/tools/command-sandbox.js +73 -0
- package/dist/tools/edit-file.d.ts +8 -0
- package/dist/tools/edit-file.js +39 -16
- package/dist/tools/edit-match.d.ts +16 -0
- package/dist/tools/edit-match.js +115 -0
- package/dist/tools/fetch-url.d.ts +15 -1
- package/dist/tools/fetch-url.js +7 -47
- package/dist/tools/get-diagnostics.d.ts +14 -0
- package/dist/tools/get-diagnostics.js +44 -0
- package/dist/tools/glob-filter.d.ts +7 -0
- package/dist/tools/glob-filter.js +12 -0
- package/dist/tools/html-to-markdown.d.ts +13 -0
- package/dist/tools/html-to-markdown.js +507 -0
- package/dist/tools/index.d.ts +5 -1
- package/dist/tools/index.js +11 -1
- package/dist/tools/list-files.d.ts +1 -0
- package/dist/tools/list-files.js +17 -5
- package/dist/tools/list-symbols.js +2 -2
- package/dist/tools/network-policy.d.ts +5 -0
- package/dist/tools/network-policy.js +77 -0
- package/dist/tools/office-docs.d.ts +6 -0
- package/dist/tools/office-docs.js +393 -0
- package/dist/tools/permission-rules.js +55 -5
- package/dist/tools/read-file.d.ts +2 -0
- package/dist/tools/read-file.js +47 -10
- package/dist/tools/read-image.js +2 -2
- package/dist/tools/read-only.d.ts +1 -1
- package/dist/tools/read-only.js +4 -0
- package/dist/tools/repo-clone.d.ts +40 -0
- package/dist/tools/repo-clone.js +218 -0
- package/dist/tools/result-cap.d.ts +8 -0
- package/dist/tools/result-cap.js +44 -0
- package/dist/tools/run-command.d.ts +18 -1
- package/dist/tools/run-command.js +44 -9
- package/dist/tools/search-files.js +12 -53
- package/dist/tools/search-worker.d.ts +23 -0
- package/dist/tools/search-worker.js +86 -0
- package/dist/tools/shared.d.ts +14 -1
- package/dist/tools/shared.js +76 -4
- package/dist/tools/shell.d.ts +27 -0
- package/dist/tools/shell.js +80 -0
- package/dist/tools/sub-agent.d.ts +1 -1
- package/dist/tools/sub-agent.js +4 -1
- package/dist/tools/suggest-plan.d.ts +18 -0
- package/dist/tools/suggest-plan.js +28 -0
- package/dist/types.d.ts +132 -1
- package/dist/wakeup/wakeup-tools.d.ts +22 -0
- package/dist/wakeup/wakeup-tools.js +34 -0
- package/dist/wakeup/wakeup.d.ts +75 -0
- package/dist/wakeup/wakeup.js +151 -0
- package/dist/worktree/health.d.ts +51 -0
- package/dist/worktree/health.js +186 -0
- package/dist/worktree/index.d.ts +4 -0
- package/dist/worktree/index.js +2 -0
- package/dist/worktree/setup.d.ts +51 -0
- package/dist/worktree/setup.js +173 -0
- package/dist/worktree/worktree.d.ts +7 -0
- package/dist/worktree/worktree.js +9 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export { Agent, applySandbox } from './agent/agent.js';
|
|
2
2
|
export { LoopGuard } from './agent/loop-guard.js';
|
|
3
3
|
export { enhancePrompt } from './agent/enhance-prompt.js';
|
|
4
|
+
export { generateShellCommand, shellKindOf, commandRisk } from './agent/shell-command.js';
|
|
5
|
+
export type { ShellKind } from './agent/shell-command.js';
|
|
4
6
|
export { stripThinkTags } from './agent/think-tags.js';
|
|
5
|
-
export { createGitHubCreateTool, createGitHubReadTool, createGitHubTools, githubFromEnv, parseRemote, type GitHubConfig, type PullRequestReport, type RepoRef, } from './github/github-tools.js';
|
|
7
|
+
export { createGitHubCreateTool, createGitHubReadTool, createGitHubTools, githubFromEnv, parseRemote, type GitHubConfig, type PullRequestReport, repoFor, type RepoRef, } from './github/github-tools.js';
|
|
8
|
+
export { defaultBranch, findPullRequest, openPullRequest, type NewPullRequest, type PullRequestSummary } from './github/pr.js';
|
|
6
9
|
export { createWebSearchTool, searchWeb, WEB_SEARCH_PROVIDERS, webSearchFromEnv, webSearchProblem, type WebSearchConfig, type WebSearchProvider, type WebSearchResult, } from './tools/web-search.js';
|
|
7
10
|
export { attachmentKind, attachmentBytes, attachmentParts, attachmentProblem, describeAttachment, detectMediaType, loadAttachment, makeAttachment, mediaPartTokens, MAX_ATTACHMENT_BYTES, MAX_IMAGE_ATTACHMENT_BYTES, type Attachment, type AttachmentKind, } from './attachments.js';
|
|
8
11
|
export type { CredentialStore } from './credentials/types.js';
|
|
@@ -33,17 +36,18 @@ export type { StaleOptions } from './memory/stale.js';
|
|
|
33
36
|
export type { LoadedMemory, InjectOptions, MemoryInjection, MemorySection, MemorySource, MemoryType, SectionMeta, } from './memory/memory-store.js';
|
|
34
37
|
export { MAX_BODY_CHARS } from './tools/memory.js';
|
|
35
38
|
export type { MemoryForgetResult, MemoryReadResult, MemoryWriteResult } from './tools/memory.js';
|
|
36
|
-
export { buildLlmSummarizer, compactMessages, estimateMessageTokens, estimateTokens, getModelWindowTokens, shouldCompact, } from './context/compaction.js';
|
|
39
|
+
export { buildLlmSummarizer, COMPACTION_SUMMARY_PREFIX, compactMessages, estimateMessageTokens, isCompactionSummary, estimateTokens, getModelWindowTokens, windowIsGuess, shouldCompact, } from './context/compaction.js';
|
|
37
40
|
export type { CompactionResult, Summarizer } from './context/compaction.js';
|
|
38
41
|
export { defaultModelFor, detectProvider, envVarForProvider, fastDefaultFor, hasProviderKey, readModelConfigFromEnv, resolveApiKey, SUPPORTED_PROVIDERS, } from './config.js';
|
|
39
|
-
export { loadMcpConfig, parseMcpConfig, connectAll, connectOne, closeAll, mcpResultToValue, mcpInstructionsBlock, createMcpResourceTools, jsonSchemaToZod, } from './mcp/index.js';
|
|
42
|
+
export { loadMcpConfig, parseMcpConfig, connectAll, connectOne, closeAll, mcpResultToValue, mcpInstructionsBlock, mcpToolName, mcpToolPrefix, createMcpResourceTools, jsonSchemaToZod, } from './mcp/index.js';
|
|
40
43
|
export type { McpConfigFile, McpServerSpec, ConnectedMcpServer, } from './mcp/index.js';
|
|
41
44
|
export { createLanguageModel, formatModelId, pickAvailableProvider, resolveModelFromEnv, resolveModelFromEnvAsync } from './providers.js';
|
|
42
|
-
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
43
|
-
export type { Session, ListEntry, FormatOptions, SessionUpdate, WatchSessionOptions, SessionMatch, SearchSessionsOptions, SessionPruneOptions, SessionPruneResult } from './sessions/index.js';
|
|
45
|
+
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, displayMessages, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
46
|
+
export type { Session, ListEntry, MessageFeedback, FormatOptions, SessionUpdate, WatchSessionOptions, SessionMatch, SearchSessionsOptions, SessionPruneOptions, SessionPruneResult } from './sessions/index.js';
|
|
44
47
|
export { commandDirs, expandCustomCommand, formatCustomCommands, loadCustomCommands, parseCommandFile, type CustomCommand, } from './commands/custom-commands.js';
|
|
45
48
|
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, gitDiffTool, dependencyAuditTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
46
|
-
export type { AgentConfig, AgentEvent, AgentRunOptions, AgentRunReason, AgentRunResult, AnyLanguageModel, ApprovalDecision, CommandRunner, ModelRouter, VerifyConfig, ApprovalRequest, LanguageModelFactory, ModelConfig, PricePerMillionTokens, ProviderName, RedactOptions, TodoItem, ToolContext, UserQuestion, ToolDefinition, ToolPolicy, ToolSandbox, } from './types.js';
|
|
49
|
+
export type { AgentConfig, AgentEvent, ApprovalSource, AgentRunOptions, AgentRunReason, AgentRunResult, AnyLanguageModel, ApprovalDecision, CommandRunner, ModelRouter, VerifyConfig, ApprovalRequest, LanguageModelFactory, ModelConfig, PricePerMillionTokens, ProviderName, RedactOptions, TodoItem, ToolContext, UserQuestion, ToolDefinition, ToolPolicy, ToolSandbox, } from './types.js';
|
|
50
|
+
export { humanize, runReasonLabel, toolLabel } from './human-text.js';
|
|
47
51
|
export type { CacheKeyParts, CacheStats } from './tools/index.js';
|
|
48
52
|
export type { RedactionRule, RedactionResult } from './tools/index.js';
|
|
49
53
|
export { buildSkillsBlock, builtinSkills, composeSkillsPrompt, discoverSkills, fetchSkillsCatalog, installSkillFromCatalog, loadSkillsRegistry, loadSkillsRegistryAsync, parseSkill, parseSkillsDir, resolveSkillRoots, scoreSkill, searchSkills, selectSkills, skillsRegistryFromList, DEFAULT_SKILL_CATALOG_URL, GLOBAL_SKILLS_DIR, LOCAL_SKILLS_DIR, PROJECT_SKILLS_DIR, SKILL_CATALOG_VERSION, } from './skills/index.js';
|
|
@@ -89,8 +93,8 @@ export { computeUnifiedDiff, computeDiffSummary, type DiffOptions, type DiffResu
|
|
|
89
93
|
export { defaultRetryPrompt, formatZodError, isStructuredOutputError, loadSchemaFile, runStructuredAgent, StructuredOutputError, validateFinalText, } from './structured/index.js';
|
|
90
94
|
export type { StructuredRunOptions, StructuredRunResult } from './structured/index.js';
|
|
91
95
|
export type { ZodTypeAny } from './structured/index.js';
|
|
92
|
-
export { branchChangedFiles, branchDiff, commitAllInWorktree, compareWorktreeContexts, deleteBranch, mergeBranch, snapshotWorktreeContext, WorktreeError, WorktreeManager, } from './worktree/index.js';
|
|
93
|
-
export type { MergeResult, WorktreeCommit, CreateOptions, RemoveOptions, RemoveResult, WorktreeContextSnapshot, WorktreeInfo, WorktreeMismatchKind, WorktreeMismatchResult, } from './worktree/index.js';
|
|
96
|
+
export { branchChangedFiles, branchDiff, commitAllInWorktree, compareWorktreeContexts, copyIntoWorktree, deleteBranch, doctorWorktrees, inspectWorktrees, mergeBranch, pruneMissingWorktrees, removeStrayFolder, runSetupScript, setupWorktree, snapshotWorktreeContext, worktreeStats, WorktreeError, WorktreeManager, } from './worktree/index.js';
|
|
97
|
+
export type { MergeResult, WorktreeCommit, CreateOptions, RemoveOptions, RemoveResult, WorktreeContextSnapshot, WorktreeInfo, WorktreeMismatchKind, WorktreeMismatchResult, HealthFinding, ListedWorktree, WorktreeInspection, WorktreeStats, CopyOptions, CopyResult, ScriptOptions, ScriptResult, SetupOptions, SetupOutcome, } from './worktree/index.js';
|
|
94
98
|
export { formatSteeringLine, isSafeSteeringName, loadSteering, overrideFilePath, parseSteering, pathMatchesGlob, readOverride, selectAtStart, selectOnToolTouch, setSteeringDisabled, stripSteering, wrapSteering, } from './steering/index.js';
|
|
95
99
|
export type { StartSelection, SteeringConfig, SteeringDoc, SteeringInclusion, SteeringLoadResult, SteeringSkip, } from './steering/index.js';
|
|
96
100
|
export { CONFIG_KEY_COVERAGE, FORGE_CONFIG_SCHEMA } from './config-schema.js';
|
|
@@ -100,9 +104,15 @@ export { detectStackFacts, stackBlock, MAX_STACK_LIBRARIES, type StackFacts } fr
|
|
|
100
104
|
export { pickAuditors, type AuditFinding, type AuditorPlan } from './tools/dependency-audit.js';
|
|
101
105
|
export { shellEnv } from './tools/shell-env.js';
|
|
102
106
|
export { previewPatch } from './tools/apply-patch.js';
|
|
107
|
+
export { applyTextEdit } from './tools/edit-file.js';
|
|
108
|
+
export { catalogEntry, loadModelCatalog, type CatalogEntry, type CatalogSource } from './catalog/models-dev.js';
|
|
109
|
+
export { MAX_HORIZON_MS, MAX_PER_SESSION as MAX_WAKEUPS, MIN_DELAY_MS as MIN_WAKEUP_DELAY_MS, WakeupScheduler, resolveWakeupTime, wakeupMessage } from './wakeup/wakeup.js';
|
|
110
|
+
export type { Wakeup, WakeupSchedulerOptions, WakeupStore } from './wakeup/wakeup.js';
|
|
111
|
+
export { isContextOverflowError, retryDecision, withModelRetry } from './agent/retry.js';
|
|
103
112
|
export type { PatchPreview } from './tools/apply-patch.js';
|
|
104
113
|
export { applyPatchTool, parsePatch, patchedPaths } from './tools/apply-patch.js';
|
|
105
|
-
export { buildEmbedder, type EmbedderSpec } from './semantic/embedder.js';
|
|
114
|
+
export { buildEmbedder, embedderDestination, type EmbedderSpec } from './semantic/embedder.js';
|
|
115
|
+
export { deleteSemanticIndex, SemanticConsentError, type SemanticStatus } from './semantic/semantic-index.js';
|
|
106
116
|
export { parseExtensions, type SemanticOptions } from './semantic/semantic-index.js';
|
|
107
117
|
export { cleanDigest, generateSessionDigest, shouldDigest, type DigestItem } from './memory/session-digest.js';
|
|
108
118
|
export { buildExtraInstructionsBlock } from './steering/extra-instructions.js';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { Agent, applySandbox } from './agent/agent.js';
|
|
2
2
|
export { LoopGuard } from './agent/loop-guard.js';
|
|
3
3
|
export { enhancePrompt } from './agent/enhance-prompt.js';
|
|
4
|
+
export { generateShellCommand, shellKindOf, commandRisk } from './agent/shell-command.js';
|
|
4
5
|
export { stripThinkTags } from './agent/think-tags.js';
|
|
5
|
-
export { createGitHubCreateTool, createGitHubReadTool, createGitHubTools, githubFromEnv, parseRemote, } from './github/github-tools.js';
|
|
6
|
+
export { createGitHubCreateTool, createGitHubReadTool, createGitHubTools, githubFromEnv, parseRemote, repoFor, } from './github/github-tools.js';
|
|
7
|
+
export { defaultBranch, findPullRequest, openPullRequest } from './github/pr.js';
|
|
6
8
|
export { createWebSearchTool, searchWeb, WEB_SEARCH_PROVIDERS, webSearchFromEnv, webSearchProblem, } from './tools/web-search.js';
|
|
7
9
|
export { attachmentKind, attachmentBytes, attachmentParts, attachmentProblem, describeAttachment, detectMediaType, loadAttachment, makeAttachment, mediaPartTokens, MAX_ATTACHMENT_BYTES, MAX_IMAGE_ATTACHMENT_BYTES, } from './attachments.js';
|
|
8
10
|
export { CREDENTIAL_SERVICE_NAME, credentialAccountKey } from './credentials/index.js';
|
|
@@ -20,13 +22,14 @@ export { buildMemoryBlock, composeSectionUpdate, findProjectMemoryRoot, globalMe
|
|
|
20
22
|
export { scoreSections, tokenize } from './memory/rank.js';
|
|
21
23
|
export { checkStale, staleKey } from './memory/stale.js';
|
|
22
24
|
export { MAX_BODY_CHARS } from './tools/memory.js';
|
|
23
|
-
export { buildLlmSummarizer, compactMessages, estimateMessageTokens, estimateTokens, getModelWindowTokens, shouldCompact, } from './context/compaction.js';
|
|
25
|
+
export { buildLlmSummarizer, COMPACTION_SUMMARY_PREFIX, compactMessages, estimateMessageTokens, isCompactionSummary, estimateTokens, getModelWindowTokens, windowIsGuess, shouldCompact, } from './context/compaction.js';
|
|
24
26
|
export { defaultModelFor, detectProvider, envVarForProvider, fastDefaultFor, hasProviderKey, readModelConfigFromEnv, resolveApiKey, SUPPORTED_PROVIDERS, } from './config.js';
|
|
25
|
-
export { loadMcpConfig, parseMcpConfig, connectAll, connectOne, closeAll, mcpResultToValue, mcpInstructionsBlock, createMcpResourceTools, jsonSchemaToZod, } from './mcp/index.js';
|
|
27
|
+
export { loadMcpConfig, parseMcpConfig, connectAll, connectOne, closeAll, mcpResultToValue, mcpInstructionsBlock, mcpToolName, mcpToolPrefix, createMcpResourceTools, jsonSchemaToZod, } from './mcp/index.js';
|
|
26
28
|
export { createLanguageModel, formatModelId, pickAvailableProvider, resolveModelFromEnv, resolveModelFromEnvAsync } from './providers.js';
|
|
27
|
-
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
29
|
+
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, displayMessages, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
28
30
|
export { commandDirs, expandCustomCommand, formatCustomCommands, loadCustomCommands, parseCommandFile, } from './commands/custom-commands.js';
|
|
29
31
|
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, gitDiffTool, dependencyAuditTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
32
|
+
export { humanize, runReasonLabel, toolLabel } from './human-text.js';
|
|
30
33
|
// Skills system
|
|
31
34
|
export { buildSkillsBlock, builtinSkills, composeSkillsPrompt, discoverSkills, fetchSkillsCatalog, installSkillFromCatalog, loadSkillsRegistry, loadSkillsRegistryAsync, parseSkill, parseSkillsDir, resolveSkillRoots, scoreSkill, searchSkills, selectSkills, skillsRegistryFromList, DEFAULT_SKILL_CATALOG_URL, GLOBAL_SKILLS_DIR, LOCAL_SKILLS_DIR, PROJECT_SKILLS_DIR, SKILL_CATALOG_VERSION, } from './skills/index.js';
|
|
32
35
|
export { cosine, embedderFromEnv, hashingEmbedder, openAiCompatibleEmbedder, } from './semantic/embedder.js';
|
|
@@ -70,7 +73,7 @@ export { defaultRetryPrompt, formatZodError, isStructuredOutputError, loadSchema
|
|
|
70
73
|
// Lets child agents work in isolated git worktrees so parallel work
|
|
71
74
|
// doesn't clobber the main checkout. Lifecycle: create → use → remove.
|
|
72
75
|
// `pruneStale()` cleans up worktrees left behind by crashed sessions.
|
|
73
|
-
export { branchChangedFiles, branchDiff, commitAllInWorktree, compareWorktreeContexts, deleteBranch, mergeBranch, snapshotWorktreeContext, WorktreeError, WorktreeManager, } from './worktree/index.js';
|
|
76
|
+
export { branchChangedFiles, branchDiff, commitAllInWorktree, compareWorktreeContexts, copyIntoWorktree, deleteBranch, doctorWorktrees, inspectWorktrees, mergeBranch, pruneMissingWorktrees, removeStrayFolder, runSetupScript, setupWorktree, snapshotWorktreeContext, worktreeStats, WorktreeError, WorktreeManager, } from './worktree/index.js';
|
|
74
77
|
// Steering files (SP3a)
|
|
75
78
|
export { formatSteeringLine, isSafeSteeringName, loadSteering, overrideFilePath, parseSteering, pathMatchesGlob, readOverride, selectAtStart, selectOnToolTouch, setSteeringDisabled, stripSteering, wrapSteering, } from './steering/index.js';
|
|
76
79
|
export { CONFIG_KEY_COVERAGE, FORGE_CONFIG_SCHEMA } from './config-schema.js';
|
|
@@ -80,8 +83,13 @@ export { detectStackFacts, stackBlock, MAX_STACK_LIBRARIES } from './agent/stack
|
|
|
80
83
|
export { pickAuditors } from './tools/dependency-audit.js';
|
|
81
84
|
export { shellEnv } from './tools/shell-env.js';
|
|
82
85
|
export { previewPatch } from './tools/apply-patch.js';
|
|
86
|
+
export { applyTextEdit } from './tools/edit-file.js';
|
|
87
|
+
export { catalogEntry, loadModelCatalog } from './catalog/models-dev.js';
|
|
88
|
+
export { MAX_HORIZON_MS, MAX_PER_SESSION as MAX_WAKEUPS, MIN_DELAY_MS as MIN_WAKEUP_DELAY_MS, WakeupScheduler, resolveWakeupTime, wakeupMessage } from './wakeup/wakeup.js';
|
|
89
|
+
export { isContextOverflowError, retryDecision, withModelRetry } from './agent/retry.js';
|
|
83
90
|
export { applyPatchTool, parsePatch, patchedPaths } from './tools/apply-patch.js';
|
|
84
|
-
export { buildEmbedder } from './semantic/embedder.js';
|
|
91
|
+
export { buildEmbedder, embedderDestination } from './semantic/embedder.js';
|
|
92
|
+
export { deleteSemanticIndex, SemanticConsentError } from './semantic/semantic-index.js';
|
|
85
93
|
export { parseExtensions } from './semantic/semantic-index.js';
|
|
86
94
|
export { cleanDigest, generateSessionDigest, shouldDigest } from './memory/session-digest.js';
|
|
87
95
|
export { buildExtraInstructionsBlock } from './steering/extra-instructions.js';
|
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
* model scaffolds MySQL with invoicing. In the system message it cannot be
|
|
9
9
|
* forgotten.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* (`agent.ts:231`), so this block enters the prompt once, on a session's first
|
|
14
|
-
* turn, and rides inside `history[0]` from then on.
|
|
11
|
+
* The system message is rebuilt on every turn (`buildSystemContent`, RB-57), so this block always carries the
|
|
12
|
+
* answers given so far.
|
|
15
13
|
*/
|
|
16
14
|
import type { Answer } from './types.js';
|
|
17
15
|
export declare function renderAnswersBlock(answers: readonly Answer[]): string;
|
|
@@ -4,6 +4,8 @@ export interface LspConfig {
|
|
|
4
4
|
servers?: Record<string, LspServerSpec>;
|
|
5
5
|
/** How long to wait for a server to report on a file. Default 10s. */
|
|
6
6
|
waitMs?: number;
|
|
7
|
+
/** Also report warnings, not only errors (the verify loop wants errors only). */
|
|
8
|
+
includeWarnings?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export interface FileDiagnostics {
|
|
9
11
|
file: string;
|
|
@@ -15,6 +17,8 @@ export interface LspReport {
|
|
|
15
17
|
/** Extensions whose server could not be started (not installed, crashed). */
|
|
16
18
|
skipped: string[];
|
|
17
19
|
}
|
|
20
|
+
/** Whether a file's type has a language server configured (built-in table or an override). */
|
|
21
|
+
export declare function hasServerFor(file: string, config?: LspConfig): boolean;
|
|
18
22
|
/** Runs the matching language server over `files` (paths relative to `cwd` or absolute). */
|
|
19
23
|
export declare function collectErrors(files: string[], cwd: string, config?: LspConfig): Promise<LspReport>;
|
|
20
24
|
/** Plain-text rendering fed to the model, in `file:line:col: message` form. */
|
package/dist/lsp/diagnostics.js
CHANGED
|
@@ -23,6 +23,11 @@ const DEFAULT_LANGUAGES = {
|
|
|
23
23
|
const DEFAULT_WAIT_MS = 10_000;
|
|
24
24
|
const START_TIMEOUT_MS = 15_000;
|
|
25
25
|
const MAX_PER_FILE = 20;
|
|
26
|
+
/** Whether a file's type has a language server configured (built-in table or an override). */
|
|
27
|
+
export function hasServerFor(file, config = {}) {
|
|
28
|
+
const ext = path.extname(file).toLowerCase();
|
|
29
|
+
return Boolean(config.servers?.[ext] ?? DEFAULT_LANGUAGES[ext]);
|
|
30
|
+
}
|
|
26
31
|
/** Runs the matching language server over `files` (paths relative to `cwd` or absolute). */
|
|
27
32
|
export async function collectErrors(files, cwd, config = {}) {
|
|
28
33
|
const waitMs = config.waitMs ?? DEFAULT_WAIT_MS;
|
|
@@ -54,7 +59,7 @@ export async function collectErrors(files, cwd, config = {}) {
|
|
|
54
59
|
const text = await readFile(f.abs, 'utf8').catch(() => null);
|
|
55
60
|
if (text === null)
|
|
56
61
|
continue;
|
|
57
|
-
const diagnostics = (await client.diagnose(pathToFileURL(f.abs).href, f.languageId, text, waitMs)).filter((d) => d.severity === 'error');
|
|
62
|
+
const diagnostics = (await client.diagnose(pathToFileURL(f.abs).href, f.languageId, text, waitMs)).filter((d) => d.severity === 'error' || (config.includeWarnings === true && d.severity === 'warning'));
|
|
58
63
|
if (diagnostics.length > 0)
|
|
59
64
|
report.errors.push({ file: path.relative(cwd, f.abs) || f.abs, diagnostics });
|
|
60
65
|
}
|
|
@@ -71,7 +76,8 @@ export function formatErrors(errors) {
|
|
|
71
76
|
.map(({ file, diagnostics }) => {
|
|
72
77
|
const lines = diagnostics.slice(0, MAX_PER_FILE).map((d) => {
|
|
73
78
|
const tag = [d.source, d.code].filter((x) => x !== undefined && x !== '').join(' ');
|
|
74
|
-
|
|
79
|
+
const level = d.severity === 'error' ? '' : `${d.severity}: `;
|
|
80
|
+
return `${file}:${d.line}:${d.column}: ${level}${d.message}${tag ? ` (${tag})` : ''}`;
|
|
75
81
|
});
|
|
76
82
|
if (diagnostics.length > MAX_PER_FILE)
|
|
77
83
|
lines.push(`... ${diagnostics.length - MAX_PER_FILE} more in ${file}`);
|
package/dist/lsp/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { LspClient } from './client.js';
|
|
2
2
|
export type { LspDiagnostic, LspServerSpec, LspSeverity } from './client.js';
|
|
3
|
-
export { collectErrors, formatErrors } from './diagnostics.js';
|
|
3
|
+
export { collectErrors, formatErrors, hasServerFor } from './diagnostics.js';
|
|
4
4
|
export type { FileDiagnostics, LspConfig, LspReport } from './diagnostics.js';
|
package/dist/lsp/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { LspClient } from './client.js';
|
|
2
|
-
export { collectErrors, formatErrors } from './diagnostics.js';
|
|
2
|
+
export { collectErrors, formatErrors, hasServerFor } from './diagnostics.js';
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { loadMcpConfig, parseMcpConfig } from './mcp-config.js';
|
|
2
2
|
export type { McpConfigFile, McpServerSpec } from './mcp-config.js';
|
|
3
3
|
export { jsonSchemaToZod } from './json-schema-to-zod.js';
|
|
4
|
-
export { connectAll, connectOne, closeAll, mcpInstructionsBlock, mcpResultToValue, McpAuthRequiredError } from './mcp-client.js';
|
|
4
|
+
export { connectAll, connectOne, closeAll, mcpInstructionsBlock, mcpResultToValue, mcpToolName, mcpToolPrefix, McpAuthRequiredError } from './mcp-client.js';
|
|
5
5
|
export type { ConnectOptions } from './mcp-client.js';
|
|
6
6
|
export { forgetSavedAuth, defaultMcpAuthDir } from './oauth.js';
|
|
7
7
|
export type { McpOAuthOptions } from './oauth.js';
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { loadMcpConfig, parseMcpConfig } from './mcp-config.js';
|
|
2
2
|
export { jsonSchemaToZod } from './json-schema-to-zod.js';
|
|
3
|
-
export { connectAll, connectOne, closeAll, mcpInstructionsBlock, mcpResultToValue, McpAuthRequiredError } from './mcp-client.js';
|
|
3
|
+
export { connectAll, connectOne, closeAll, mcpInstructionsBlock, mcpResultToValue, mcpToolName, mcpToolPrefix, McpAuthRequiredError } from './mcp-client.js';
|
|
4
4
|
export { forgetSavedAuth, defaultMcpAuthDir } from './oauth.js';
|
|
5
5
|
export { createMcpResourceTools } from './resource-tools.js';
|
|
6
6
|
export { BUILTIN_MCP_CATALOG, loadMcpCatalog } from './catalog.js';
|
|
@@ -68,11 +68,9 @@ export function jsonSchemaToZod(schema) {
|
|
|
68
68
|
.pipe(objectZod)
|
|
69
69
|
: objectZod;
|
|
70
70
|
}
|
|
71
|
-
else if (s.additionalProperties === true) {
|
|
72
|
-
inner = z.record(z.string(), z.any());
|
|
73
|
-
}
|
|
74
71
|
else {
|
|
75
|
-
|
|
72
|
+
// Any object. Not z.record(): its JSON Schema carries `propertyNames`, a keyword Gemini's schema input does not list.
|
|
73
|
+
inner = z.looseObject({});
|
|
76
74
|
}
|
|
77
75
|
break;
|
|
78
76
|
}
|
package/dist/mcp/mcp-client.d.ts
CHANGED
|
@@ -26,6 +26,20 @@ export declare function connectOne(name: string, spec: McpServerSpec, options?:
|
|
|
26
26
|
export declare function mcpInstructionsBlock(servers: readonly ConnectedMcpServer[]): string;
|
|
27
27
|
/** Close all clients and their underlying transports. */
|
|
28
28
|
export declare function closeAll(servers: ConnectedMcpServer[]): Promise<void>;
|
|
29
|
+
/** The start of every tool name of one server. Names a provider accepts only: letters, digits, `_` and `-`. */
|
|
30
|
+
export declare function mcpToolPrefix(serverName: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* The name the model sees for a server's tool. OpenAI and Anthropic refuse a tool name with any other character or
|
|
33
|
+
* over 64 characters, and one refused name fails the whole request. A name that needed cleaning or cutting gets a
|
|
34
|
+
* short hash of the original pair so two different tools never become one; the call itself still uses the server's
|
|
35
|
+
* own tool name.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mcpToolName(serverName: string, toolName: string): string;
|
|
38
|
+
export declare function mcpToolToForgeTool(serverName: string, mcpTool: {
|
|
39
|
+
name: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
inputSchema?: unknown;
|
|
42
|
+
}, getClient: () => Client, timeout?: number, reconnect?: () => Promise<Client>): ToolDefinition;
|
|
29
43
|
/**
|
|
30
44
|
* Reduce an MCP `CallToolResult` to a model-friendly value.
|
|
31
45
|
*
|
package/dist/mcp/mcp-client.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* - **streamable-http**: `url` + optional `headers`. The 2025-03-26 modern
|
|
22
22
|
* transport. Uses the SDK's `StreamableHTTPClientTransport`.
|
|
23
23
|
*/
|
|
24
|
+
import { createHash } from 'node:crypto';
|
|
24
25
|
import { readFileSync } from 'node:fs';
|
|
25
26
|
import { dirname, join } from 'node:path';
|
|
26
27
|
import { fileURLToPath } from 'node:url';
|
|
@@ -32,6 +33,7 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/
|
|
|
32
33
|
import { filterMcpServers, getOrgPolicy } from '../policy/policy.js';
|
|
33
34
|
import { jsonSchemaToZod } from './json-schema-to-zod.js';
|
|
34
35
|
import { ForgeOAuthProvider, McpAuthRequiredError, defaultMcpAuthDir, readSavedAuth } from './oauth.js';
|
|
36
|
+
import { clampOutput } from '../tools/run-command.js';
|
|
35
37
|
/**
|
|
36
38
|
* Self-identifying info we send to every MCP server during the `initialize`
|
|
37
39
|
* handshake. Version is read from our own package.json so it stays in sync
|
|
@@ -90,6 +92,32 @@ function isUnauthorized(err) {
|
|
|
90
92
|
}
|
|
91
93
|
/** Connect to a single server and pull its tools. */
|
|
92
94
|
export async function connectOne(name, spec, options = {}) {
|
|
95
|
+
let current = await openClient(name, spec, options);
|
|
96
|
+
// One restart at a time: calls that find the server gone together share one new process (G7).
|
|
97
|
+
let restarting;
|
|
98
|
+
const reconnect = () => {
|
|
99
|
+
restarting ??= (async () => {
|
|
100
|
+
await current.close().catch(() => undefined);
|
|
101
|
+
current = await openClient(name, spec, options);
|
|
102
|
+
return current;
|
|
103
|
+
})().finally(() => {
|
|
104
|
+
restarting = undefined;
|
|
105
|
+
});
|
|
106
|
+
return restarting;
|
|
107
|
+
};
|
|
108
|
+
const { tools: mcpTools } = await current.listTools(undefined, spec.timeout ? { timeout: spec.timeout } : undefined);
|
|
109
|
+
const tools = mcpTools.map((t) => mcpToolToForgeTool(name, t, () => current, spec.timeout, reconnect));
|
|
110
|
+
return {
|
|
111
|
+
name,
|
|
112
|
+
get client() {
|
|
113
|
+
return current;
|
|
114
|
+
},
|
|
115
|
+
tools,
|
|
116
|
+
instructions: current.getInstructions()?.trim() || undefined,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Start the transport, run the handshake (and the sign-in when the server wants one) and return the live client. */
|
|
120
|
+
async function openClient(name, spec, options) {
|
|
93
121
|
const timeout = spec.timeout ? { timeout: spec.timeout } : undefined;
|
|
94
122
|
let client = new Client(CLIENT_INFO, { capabilities: {} });
|
|
95
123
|
const oauth = options.oauth;
|
|
@@ -134,9 +162,12 @@ export async function connectOne(name, spec, options = {}) {
|
|
|
134
162
|
await client.connect(transport, timeout);
|
|
135
163
|
}
|
|
136
164
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
165
|
+
return client;
|
|
166
|
+
}
|
|
167
|
+
/** A call that failed because the server's process or connection is gone, not because the call itself was bad. */
|
|
168
|
+
function isConnectionLost(err) {
|
|
169
|
+
const e = err;
|
|
170
|
+
return e?.code === -32000 || (typeof e?.message === 'string' && /connection closed|not connected/i.test(e.message));
|
|
140
171
|
}
|
|
141
172
|
/**
|
|
142
173
|
* Pick the right SDK transport for the server spec. The transport type is
|
|
@@ -193,8 +224,36 @@ export async function closeAll(servers) {
|
|
|
193
224
|
* namespace of the built-in tools and tells the model which server a tool
|
|
194
225
|
* came from at a glance.
|
|
195
226
|
*/
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
const MAX_TOOL_NAME = 64;
|
|
228
|
+
const MAX_SERVER_PART = 30;
|
|
229
|
+
function cleanNamePart(s) {
|
|
230
|
+
return s.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
231
|
+
}
|
|
232
|
+
function shortHash(s) {
|
|
233
|
+
return createHash('sha256').update(s).digest('hex').slice(0, 8);
|
|
234
|
+
}
|
|
235
|
+
/** The start of every tool name of one server. Names a provider accepts only: letters, digits, `_` and `-`. */
|
|
236
|
+
export function mcpToolPrefix(serverName) {
|
|
237
|
+
return `mcp__${cleanNamePart(serverName).slice(0, MAX_SERVER_PART)}__`;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* The name the model sees for a server's tool. OpenAI and Anthropic refuse a tool name with any other character or
|
|
241
|
+
* over 64 characters, and one refused name fails the whole request. A name that needed cleaning or cutting gets a
|
|
242
|
+
* short hash of the original pair so two different tools never become one; the call itself still uses the server's
|
|
243
|
+
* own tool name.
|
|
244
|
+
*/
|
|
245
|
+
export function mcpToolName(serverName, toolName) {
|
|
246
|
+
const prefix = mcpToolPrefix(serverName);
|
|
247
|
+
const body = cleanNamePart(toolName);
|
|
248
|
+
const name = prefix + body;
|
|
249
|
+
const untouched = prefix === `mcp__${serverName}__` && body === toolName && name.length <= MAX_TOOL_NAME;
|
|
250
|
+
if (untouched)
|
|
251
|
+
return name;
|
|
252
|
+
const hash = shortHash(`${serverName}\u0000${toolName}`);
|
|
253
|
+
return `${name.slice(0, MAX_TOOL_NAME - hash.length - 1)}_${hash}`;
|
|
254
|
+
}
|
|
255
|
+
export function mcpToolToForgeTool(serverName, mcpTool, getClient, timeout, reconnect) {
|
|
256
|
+
const fullName = mcpToolName(serverName, mcpTool.name);
|
|
198
257
|
const description = [
|
|
199
258
|
mcpTool.description ?? '',
|
|
200
259
|
`(MCP server: ${serverName})`,
|
|
@@ -210,8 +269,24 @@ function mcpToolToForgeTool(serverName, mcpTool, client, timeout) {
|
|
|
210
269
|
// destructive so the user gets a confirmation prompt unless --auto.
|
|
211
270
|
destructive: true,
|
|
212
271
|
execute: async (args) => {
|
|
213
|
-
const
|
|
214
|
-
|
|
272
|
+
const call = (client) => client.callTool({ name: mcpTool.name, arguments: args }, undefined, timeout ? { timeout } : undefined);
|
|
273
|
+
let result;
|
|
274
|
+
try {
|
|
275
|
+
result = await call(getClient());
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
// A server that exited is started again for this call, once; any other failure goes to the caller as it is.
|
|
279
|
+
if (!reconnect || !isConnectionLost(err))
|
|
280
|
+
throw err;
|
|
281
|
+
result = await call(await reconnect());
|
|
282
|
+
}
|
|
283
|
+
const value = mcpResultToValue(result);
|
|
284
|
+
// An MCP server reports a failed call as a normal result with isError set: the model must see a failure.
|
|
285
|
+
if (result?.isError === true) {
|
|
286
|
+
const said = typeof value === 'string' ? value : value?.text;
|
|
287
|
+
throw new Error(said?.trim() || `MCP server "${serverName}" reported an error for ${mcpTool.name}.`);
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
215
290
|
},
|
|
216
291
|
};
|
|
217
292
|
}
|
|
@@ -229,16 +304,25 @@ export function mcpResultToValue(result) {
|
|
|
229
304
|
if (!Array.isArray(r.content)) {
|
|
230
305
|
return { ...r };
|
|
231
306
|
}
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
307
|
+
const texts = [];
|
|
308
|
+
let image;
|
|
309
|
+
let omitted = 0;
|
|
310
|
+
for (const c of r.content) {
|
|
311
|
+
const b = (typeof c === 'object' && c !== null ? c : {});
|
|
312
|
+
if (b.type === 'text' && typeof b.text === 'string')
|
|
313
|
+
texts.push(b.text);
|
|
314
|
+
else if (b.type === 'resource' && typeof b.resource?.text === 'string')
|
|
315
|
+
texts.push(b.resource.text);
|
|
316
|
+
// The first image goes to the model as media (like `read_image`); more images, audio and binary resources do not.
|
|
317
|
+
else if (b.type === 'image' && !image && typeof b.data === 'string' && b.mimeType?.startsWith('image/'))
|
|
318
|
+
image = { data: b.data, mime: b.mimeType };
|
|
319
|
+
else
|
|
320
|
+
omitted++;
|
|
242
321
|
}
|
|
243
|
-
|
|
322
|
+
if (omitted > 0)
|
|
323
|
+
texts.push(`[${omitted} non-text ${omitted === 1 ? 'item' : 'items'} omitted]`);
|
|
324
|
+
const text = clampOutput(texts.join('\n'));
|
|
325
|
+
if (!image)
|
|
326
|
+
return text;
|
|
327
|
+
return { text, dataUrl: `data:${image.mime};base64,${image.data}`, mime: image.mime, bytes: Math.floor((image.data.length * 3) / 4), path: 'MCP tool result' };
|
|
244
328
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateText } from 'ai';
|
|
2
|
+
import { withModelRetry } from '../agent/retry.js';
|
|
2
3
|
import { stripThinkTags } from '../agent/think-tags.js';
|
|
3
4
|
import { createLanguageModel } from '../providers.js';
|
|
4
5
|
const MAX_DIGEST_CHARS = 600;
|
|
@@ -38,7 +39,7 @@ export async function generateSessionDigest(items, model, modelFactory = createL
|
|
|
38
39
|
if (!model || !shouldDigest(items))
|
|
39
40
|
return undefined;
|
|
40
41
|
try {
|
|
41
|
-
const result = await generateText({ model: modelFactory(model), prompt: `${INSTRUCTION}\n\nConversation:\n${transcript(items)}
|
|
42
|
+
const result = await withModelRetry(() => generateText({ model: modelFactory(model), prompt: `${INSTRUCTION}\n\nConversation:\n${transcript(items)}`, maxRetries: 0 }));
|
|
42
43
|
return cleanDigest(result.text);
|
|
43
44
|
}
|
|
44
45
|
catch {
|
|
@@ -134,6 +134,9 @@ export function loadSpecialistsFromConfig(configPath, options = {}) {
|
|
|
134
134
|
out.warnings.push({ message: 'Skipped non-object entry' });
|
|
135
135
|
continue;
|
|
136
136
|
}
|
|
137
|
+
// A word-for-word copy would shadow the built-in and keep it at the version that was copied (RB-54).
|
|
138
|
+
if (isBuiltinCopy(entry))
|
|
139
|
+
continue;
|
|
137
140
|
try {
|
|
138
141
|
registerSpecialist(entry, { override: options.override ?? true, configDir });
|
|
139
142
|
out.registered.push(entry.id);
|
|
@@ -166,9 +169,19 @@ export async function saveSpecialistsToConfig(entries, configPath) {
|
|
|
166
169
|
for (const entry of entries) {
|
|
167
170
|
validateSpecialistConfig(entry, configDir);
|
|
168
171
|
}
|
|
169
|
-
|
|
172
|
+
// A word-for-word copy of a built-in would shadow it and freeze it at this version (RB-54). Drop it, and say
|
|
173
|
+
// where the call came from: nothing in Forge is meant to write one, so the stack names whoever does.
|
|
174
|
+
const copies = entries.filter(isBuiltinCopy);
|
|
175
|
+
if (copies.length > 0) {
|
|
176
|
+
console.warn(`forge: not saving ${copies.map((c) => c.id).join(', ')}: word-for-word copies of built-in agents.\n${new Error().stack ?? ''}`);
|
|
177
|
+
}
|
|
178
|
+
const file = { version: 1, specialists: entries.filter((e) => !isBuiltinCopy(e)) };
|
|
170
179
|
await updateJsonFile(path, () => file);
|
|
171
180
|
}
|
|
181
|
+
/** Same id and same prompt as a built-in: a copy, not the person's own agent. */
|
|
182
|
+
function isBuiltinCopy(entry) {
|
|
183
|
+
return BUILTIN_SPECIALISTS.some((b) => b.id === entry.id && b.systemPrompt === entry.systemPrompt);
|
|
184
|
+
}
|
|
172
185
|
/**
|
|
173
186
|
* Pure validator: returns a normalized {@link SpecialistConfig}.
|
|
174
187
|
* Throws on any rule violation with a descriptive message. Library
|
|
@@ -49,7 +49,7 @@ Stop when: you have read enough to name every file and function in the plan. Do
|
|
|
49
49
|
|
|
50
50
|
Never: write or edit files, run commands, or plan around code you have not read. If the request is unclear and the answer would change the plan, put it under Questions instead of guessing.`,
|
|
51
51
|
allowedTools: ['read_file', 'list_files', 'search_files', 'find_symbol', 'find_references', 'list_symbols', 'git_diff', 'memory_read', 'todo_write'],
|
|
52
|
-
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'sub_agent'],
|
|
52
|
+
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'bg_start', 'repo_clone', 'suggest_plan', 'sub_agent'],
|
|
53
53
|
maxIterations: 25,
|
|
54
54
|
auto: false,
|
|
55
55
|
},
|
|
@@ -129,7 +129,7 @@ Output:
|
|
|
129
129
|
|
|
130
130
|
Never: change files, run commands, or state something about this code that you did not read.`,
|
|
131
131
|
allowedTools: ['read_file', 'list_files', 'search_files', 'find_symbol', 'find_references', 'list_symbols', 'fetch_url', 'memory_read'],
|
|
132
|
-
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'sub_agent'],
|
|
132
|
+
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'bg_start', 'repo_clone', 'suggest_plan', 'sub_agent'],
|
|
133
133
|
maxIterations: 15,
|
|
134
134
|
auto: false,
|
|
135
135
|
},
|
|
@@ -156,7 +156,7 @@ Report at most ten findings. End with one line: how many hunks you reviewed and
|
|
|
156
156
|
|
|
157
157
|
Never: change files, run commands, or report something you did not confirm in the code.`,
|
|
158
158
|
allowedTools: ['read_file', 'list_files', 'search_files', 'find_symbol', 'find_references', 'list_symbols', 'git_diff', 'memory_read'],
|
|
159
|
-
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'sub_agent'],
|
|
159
|
+
forbiddenTools: ['write_file', 'edit_file', 'apply_patch', 'edit_notebook', 'run_command', 'bg_start', 'repo_clone', 'suggest_plan', 'sub_agent'],
|
|
160
160
|
maxIterations: 20,
|
|
161
161
|
auto: false,
|
|
162
162
|
},
|
package/dist/pricing.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { catalogEntry } from './catalog/models-dev.js';
|
|
1
2
|
import { overrideCost } from './model-overrides.js';
|
|
2
3
|
/**
|
|
3
4
|
* Pricing table. Keys are matched with case-insensitive substring matching
|
|
@@ -120,6 +121,17 @@ export function lookupPricing(model, override) {
|
|
|
120
121
|
return { ...cache, ...configured, known: true };
|
|
121
122
|
if (typeof model !== 'string' && LOCAL_PROVIDERS.has(model.provider))
|
|
122
123
|
return { input: 0, output: 0, known: true };
|
|
124
|
+
const listed = typeof model === 'string' ? undefined : catalogEntry(model)?.cost;
|
|
125
|
+
if (listed && listed.input > 0) {
|
|
126
|
+
return {
|
|
127
|
+
...cache,
|
|
128
|
+
input: listed.input,
|
|
129
|
+
output: listed.output,
|
|
130
|
+
...(listed.cacheRead !== undefined ? { cacheReadMultiplier: listed.cacheRead / listed.input } : {}),
|
|
131
|
+
...(listed.cacheWrite !== undefined ? { cacheWriteMultiplier: listed.cacheWrite / listed.input } : {}),
|
|
132
|
+
known: true,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
123
135
|
const id = (typeof model === 'string' ? model : model.model).toLowerCase();
|
|
124
136
|
// Strip only the OpenRouter-style 'models/' prefix so 'models/gemini-1.5-pro'
|
|
125
137
|
// resolves the same way as 'gemini-1.5-pro'. We do NOT strip provider prefixes
|
|
@@ -12,7 +12,18 @@ export interface Embedder {
|
|
|
12
12
|
/** Stable identity. Vectors from different ids are never compared; a change rebuilds the index. */
|
|
13
13
|
id: string;
|
|
14
14
|
embed(texts: string[]): Promise<number[][]>;
|
|
15
|
+
/** Where the text goes, when it leaves this process: absent for the offline embedder. */
|
|
16
|
+
remote?: {
|
|
17
|
+
host: string;
|
|
18
|
+
model: string;
|
|
19
|
+
local: boolean;
|
|
20
|
+
};
|
|
15
21
|
}
|
|
22
|
+
/** The host and model that would receive chunks of code, or undefined when nothing leaves this machine (F12). */
|
|
23
|
+
export declare function embedderDestination(e: Embedder): {
|
|
24
|
+
host: string;
|
|
25
|
+
model: string;
|
|
26
|
+
} | undefined;
|
|
16
27
|
export declare function cosine(a: number[], b: number[]): number;
|
|
17
28
|
/** Lowercased sub-tokens: splits camelCase, snake_case, digits and punctuation. */
|
|
18
29
|
export declare function tokenize(text: string): string[];
|
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
* `/v1`, LM Studio, vLLM...). Opt-in via `embedderFromEnv`; chunk text is sent
|
|
9
9
|
* to that endpoint (after secret redaction).
|
|
10
10
|
*/
|
|
11
|
+
/** The host and model that would receive chunks of code, or undefined when nothing leaves this machine (F12). */
|
|
12
|
+
export function embedderDestination(e) {
|
|
13
|
+
return e.remote && !e.remote.local ? { host: e.remote.host, model: e.remote.model } : undefined;
|
|
14
|
+
}
|
|
15
|
+
function remoteOf(baseUrl, model) {
|
|
16
|
+
let host = baseUrl;
|
|
17
|
+
try {
|
|
18
|
+
host = new URL(baseUrl).hostname.replace(/^\[|\]$/g, '');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// an address that is not a URL: report it as written, and treat it as remote
|
|
22
|
+
}
|
|
23
|
+
const local = host === 'localhost' || host === '::1' || /^127\./.test(host);
|
|
24
|
+
return { host, model, local };
|
|
25
|
+
}
|
|
11
26
|
export function cosine(a, b) {
|
|
12
27
|
let dot = 0;
|
|
13
28
|
let na = 0;
|
|
@@ -62,6 +77,7 @@ export function openAiCompatibleEmbedder(options) {
|
|
|
62
77
|
const batch = options.batchSize ?? 64;
|
|
63
78
|
return {
|
|
64
79
|
id: `openai-compat:${base}:${options.model}`,
|
|
80
|
+
remote: remoteOf(base, options.model),
|
|
65
81
|
async embed(texts) {
|
|
66
82
|
const out = [];
|
|
67
83
|
for (let i = 0; i < texts.length; i += batch) {
|