vigthoria-cli 1.13.13 → 1.13.20
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/commands/auth.js +21 -7
- package/dist/commands/background.d.ts +3 -0
- package/dist/commands/background.js +58 -1
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +121 -1
- package/dist/commands/config.js +10 -14
- package/dist/commands/legion.js +48 -13
- package/dist/index.js +107 -6
- package/dist/utils/api.d.ts +7 -0
- package/dist/utils/api.js +236 -55
- package/dist/utils/clientManifest.d.ts +9 -0
- package/dist/utils/clientManifest.js +11 -1
- package/dist/utils/command-menu.js +6 -0
- package/dist/utils/config.js +7 -5
- package/dist/utils/contextBudget.d.ts +5 -1
- package/dist/utils/contextBudget.js +7 -4
- package/dist/utils/fastAgentRouter.d.ts +2 -2
- package/dist/utils/fastAgentRouter.js +4 -5
- package/dist/utils/requestIntent.js +5 -4
- package/dist/utils/session.d.ts +18 -0
- package/dist/utils/v3-workspace-path.js +22 -2
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +3 -1
- package/scripts/release/validate-no-go-gates.sh +45 -7
package/dist/utils/api.js
CHANGED
|
@@ -659,6 +659,7 @@ export class APIClient {
|
|
|
659
659
|
getV3AgentBaseUrls(preferLocal = false) {
|
|
660
660
|
const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
|
|
661
661
|
const localTestMode = isLocalTestfarmMode();
|
|
662
|
+
const explicitV3EndpointConfigured = Boolean(process.env.VIGTHORIA_V3_AGENT_URL || process.env.V3_AGENT_URL);
|
|
662
663
|
const includeLoopbackV3Agent = process.env.VIGTHORIA_ALLOW_LOCAL_V3_AGENT === '1'
|
|
663
664
|
|| (preferLocal && isServerRuntime());
|
|
664
665
|
const localCandidates = [
|
|
@@ -672,7 +673,9 @@ export class APIClient {
|
|
|
672
673
|
const normalizedRemote = remoteCandidates
|
|
673
674
|
.filter(Boolean)
|
|
674
675
|
.map((url) => String(url).replace(/\/$/, ''));
|
|
675
|
-
|
|
676
|
+
// An explicit endpoint is an operator routing decision. External installs
|
|
677
|
+
// have none and continue to use the public Coder gateway first.
|
|
678
|
+
const urls = (preferLocal || localTestMode || explicitV3EndpointConfigured) && localCandidates.length > 0
|
|
676
679
|
? [...localCandidates, ...normalizedRemote]
|
|
677
680
|
: [...normalizedRemote, ...localCandidates];
|
|
678
681
|
return [...new Set(urls)];
|
|
@@ -696,6 +699,12 @@ export class APIClient {
|
|
|
696
699
|
}
|
|
697
700
|
return `${baseUrl}/api/v3-agent/background${cleanSuffix}`;
|
|
698
701
|
}
|
|
702
|
+
getV3AgentApprovalUrl(baseUrl) {
|
|
703
|
+
if (this.isDirectV3AgentBaseUrl(baseUrl)) {
|
|
704
|
+
return `${baseUrl}/api/agent/approval`;
|
|
705
|
+
}
|
|
706
|
+
return `${baseUrl}/api/v3-agent/approval`;
|
|
707
|
+
}
|
|
699
708
|
getOperatorBaseUrls() {
|
|
700
709
|
const configuredModelsApiUrl = String(this.config.get('modelsApiUrl') || 'https://api.vigthoria.io').replace(/\/$/, '');
|
|
701
710
|
const urls = [
|
|
@@ -876,6 +885,7 @@ export class APIClient {
|
|
|
876
885
|
extractLinkedFrontendAssets(html, entryPath) {
|
|
877
886
|
const css = new Set();
|
|
878
887
|
const js = new Set();
|
|
888
|
+
const assets = new Set();
|
|
879
889
|
const entryDir = path.posix.dirname(this.normalizeWorkspaceRelativePath(entryPath) || '.');
|
|
880
890
|
const normalizeAsset = (assetPath) => {
|
|
881
891
|
const clean = String(assetPath || '').trim();
|
|
@@ -887,7 +897,7 @@ export class APIClient {
|
|
|
887
897
|
return null;
|
|
888
898
|
}
|
|
889
899
|
if (withoutQuery.startsWith('/')) {
|
|
890
|
-
return this.normalizeWorkspaceRelativePath(withoutQuery.slice(1));
|
|
900
|
+
return this.normalizeWorkspaceRelativePath(path.posix.normalize(path.posix.join(entryDir, withoutQuery.slice(1))));
|
|
891
901
|
}
|
|
892
902
|
return this.normalizeWorkspaceRelativePath(path.posix.normalize(path.posix.join(entryDir, withoutQuery)));
|
|
893
903
|
};
|
|
@@ -906,9 +916,16 @@ export class APIClient {
|
|
|
906
916
|
js.add(resolved);
|
|
907
917
|
}
|
|
908
918
|
}
|
|
919
|
+
const assetPattern = /<(?:link|img|source|video|audio)\b[^>]+(?:href|src)=["']([^"']+)["'][^>]*>/gi;
|
|
920
|
+
while ((match = assetPattern.exec(String(html || ''))) !== null) {
|
|
921
|
+
const resolved = normalizeAsset(match[1]);
|
|
922
|
+
if (resolved)
|
|
923
|
+
assets.add(resolved);
|
|
924
|
+
}
|
|
909
925
|
return {
|
|
910
926
|
css: Array.from(css),
|
|
911
927
|
js: Array.from(js),
|
|
928
|
+
assets: Array.from(assets),
|
|
912
929
|
};
|
|
913
930
|
}
|
|
914
931
|
async buildFrontendForPreview(rootPath) {
|
|
@@ -1568,10 +1585,15 @@ export class APIClient {
|
|
|
1568
1585
|
'styles.css', 'style.css', 'README.md', 'manifest.json',
|
|
1569
1586
|
]);
|
|
1570
1587
|
/** Keep critical workspace files for server hydration when context must shrink. */
|
|
1571
|
-
compactWorkspaceFilesToBudget(files, budgetChars) {
|
|
1588
|
+
compactWorkspaceFilesToBudget(files, budgetChars, priorityPaths = [], mandatoryPaths = priorityPaths) {
|
|
1572
1589
|
const entries = Object.entries(files);
|
|
1590
|
+
const explicitPriority = new Map(priorityPaths.map((filePath, index) => [this.normalizeWorkspaceRelativePath(filePath), index]));
|
|
1591
|
+
const mandatory = new Set(mandatoryPaths.map((filePath) => this.normalizeWorkspaceRelativePath(filePath)));
|
|
1573
1592
|
const rank = (filePath) => {
|
|
1574
1593
|
const normalized = filePath.replace(/\\/g, '/');
|
|
1594
|
+
const explicitIndex = explicitPriority.get(normalized);
|
|
1595
|
+
if (explicitIndex !== undefined)
|
|
1596
|
+
return -100 + Math.min(explicitIndex, 50);
|
|
1575
1597
|
const base = normalized.split('/').pop() || '';
|
|
1576
1598
|
if (APIClient.HYDRATION_PRIORITY_BASENAMES.has(base))
|
|
1577
1599
|
return 0;
|
|
@@ -1589,6 +1611,20 @@ export class APIClient {
|
|
|
1589
1611
|
const clipped = content.length > maxContentLen ? `${content.slice(0, maxContentLen)}\n/* … truncated for remote context … */` : content;
|
|
1590
1612
|
const entryLen = JSON.stringify(filePath).length + 1 + JSON.stringify(clipped).length + 1;
|
|
1591
1613
|
if (used + entryLen > budgetChars) {
|
|
1614
|
+
const normalizedPath = this.normalizeWorkspaceRelativePath(filePath);
|
|
1615
|
+
if (mandatory.has(normalizedPath)) {
|
|
1616
|
+
trimmed[filePath] = clipped;
|
|
1617
|
+
used += entryLen;
|
|
1618
|
+
}
|
|
1619
|
+
else if (explicitPriority.has(normalizedPath)) {
|
|
1620
|
+
const envelope = JSON.stringify(filePath).length + 128;
|
|
1621
|
+
const available = Math.max(256, budgetChars - used - envelope);
|
|
1622
|
+
const dependencyClip = content.length > available
|
|
1623
|
+
? `${content.slice(0, available)}\n/* … compacted linked preview dependency … */`
|
|
1624
|
+
: content;
|
|
1625
|
+
trimmed[filePath] = dependencyClip;
|
|
1626
|
+
used += JSON.stringify(filePath).length + 1 + JSON.stringify(dependencyClip).length + 1;
|
|
1627
|
+
}
|
|
1592
1628
|
continue;
|
|
1593
1629
|
}
|
|
1594
1630
|
trimmed[filePath] = clipped;
|
|
@@ -1603,6 +1639,14 @@ export class APIClient {
|
|
|
1603
1639
|
const serverWorkspacePath = this.resolveServerBindableWorkspacePath(resolvedContext);
|
|
1604
1640
|
const promptFocus = String(resolvedContext.rawPrompt || resolvedContext.contextualPrompt || resolvedContext.prompt || '');
|
|
1605
1641
|
const localWorkspaceSummary = this.buildLocalWorkspaceSummary(localWorkspacePath, promptFocus);
|
|
1642
|
+
if (resolvedContext.workspaceFilesOutOfBand === true && localWorkspaceSummary?.workspaceFiles) {
|
|
1643
|
+
localWorkspaceSummary.workspaceHydration = {
|
|
1644
|
+
delivery: 'out-of-band',
|
|
1645
|
+
fileCount: Object.keys(localWorkspaceSummary.workspaceFiles).length,
|
|
1646
|
+
complete: true,
|
|
1647
|
+
};
|
|
1648
|
+
delete localWorkspaceSummary.workspaceFiles;
|
|
1649
|
+
}
|
|
1606
1650
|
const requestedModel = String(resolvedContext.model || resolvedContext.requestedModel || 'agent');
|
|
1607
1651
|
const resolvedModel = this.resolvePermittedModelId(requestedModel);
|
|
1608
1652
|
const localWorkspaceName = this.getDisplayWorkspaceName(localWorkspacePath);
|
|
@@ -1612,7 +1656,9 @@ export class APIClient {
|
|
|
1612
1656
|
const clientToolExecution = resolvedContext.clientToolExecution === false
|
|
1613
1657
|
? false
|
|
1614
1658
|
: (resolvedContext.clientToolExecution === true
|
|
1615
|
-
|| (
|
|
1659
|
+
|| (!serverWorkspacePath
|
|
1660
|
+
&& localMachineCapable
|
|
1661
|
+
&& ['cli', 'fork', 'local-ide', 'desktop', 'local'].includes(executionSurface)));
|
|
1616
1662
|
const publicRuntimeEnvironment = this.buildPublicRuntimeEnvironment(resolvedContext.agentRuntime, {
|
|
1617
1663
|
localWorkspacePath,
|
|
1618
1664
|
serverWorkspacePath,
|
|
@@ -1658,6 +1704,8 @@ export class APIClient {
|
|
|
1658
1704
|
requestedModelResolved: resolvedModel,
|
|
1659
1705
|
agentExecutionPolicy: resolvedContext.agentExecutionPolicy || null,
|
|
1660
1706
|
legacyFallbackAllowed: resolvedContext.legacyFallbackAllowed === true,
|
|
1707
|
+
approvalLevel: resolvedContext.approvalLevel === 'auto' ? 'auto' : 'confirm',
|
|
1708
|
+
approval_level: resolvedContext.approvalLevel === 'auto' ? 'auto' : 'confirm',
|
|
1661
1709
|
executionSurface: resolvedContext.executionSurface || 'cli',
|
|
1662
1710
|
clientSurface: resolvedContext.clientSurface || 'cli',
|
|
1663
1711
|
localMachineCapable,
|
|
@@ -1752,11 +1800,11 @@ export class APIClient {
|
|
|
1752
1800
|
const overhead = json.length - JSON.stringify(summary.workspaceFiles).length;
|
|
1753
1801
|
const budget = LIMIT - overhead - 1024;
|
|
1754
1802
|
if (budget > 0) {
|
|
1755
|
-
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, budget);
|
|
1803
|
+
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, budget, summary.focusFiles || [], summary.explicitFocusFiles || summary.focusFiles || []);
|
|
1756
1804
|
summary.workspaceFilesCompaction = Object.keys(summary.workspaceFiles).length > 0 ? 'priority-trimmed' : 'empty';
|
|
1757
1805
|
}
|
|
1758
1806
|
else if (hydrationRequired) {
|
|
1759
|
-
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, 8_000);
|
|
1807
|
+
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, 8_000, summary.focusFiles || [], summary.explicitFocusFiles || summary.focusFiles || []);
|
|
1760
1808
|
summary.workspaceFilesCompaction = 'priority-minimal';
|
|
1761
1809
|
}
|
|
1762
1810
|
else {
|
|
@@ -1781,7 +1829,7 @@ export class APIClient {
|
|
|
1781
1829
|
return finish();
|
|
1782
1830
|
}
|
|
1783
1831
|
if (hydrationRequired && summary?.workspaceFiles && typeof summary.workspaceFiles === 'object') {
|
|
1784
|
-
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, 4_000);
|
|
1832
|
+
summary.workspaceFiles = this.compactWorkspaceFilesToBudget(summary.workspaceFiles, 4_000, summary.focusFiles || [], summary.explicitFocusFiles || summary.focusFiles || []);
|
|
1785
1833
|
summary.workspaceFilesCompaction = 'priority-minimal';
|
|
1786
1834
|
json = JSON.stringify(payload);
|
|
1787
1835
|
if (json.length <= LIMIT)
|
|
@@ -2657,8 +2705,29 @@ menu {
|
|
|
2657
2705
|
};
|
|
2658
2706
|
const snapshot = this.getAgentWorkspaceSnapshot(rootPath);
|
|
2659
2707
|
const candidatePaths = snapshot.paths.filter((entry) => !/(^|[\/\\])\.vigthoria([\/\\]|$)/.test(entry));
|
|
2708
|
+
const focusFiles = this.extractExpectedWorkspaceFiles(requestFocus)
|
|
2709
|
+
.map((entry) => this.normalizeWorkspaceRelativePath(entry))
|
|
2710
|
+
.filter((entry) => candidatePaths.includes(entry));
|
|
2711
|
+
const linkedFocusAssets = [];
|
|
2712
|
+
for (const focusPath of focusFiles) {
|
|
2713
|
+
if (!/\.html?$/i.test(focusPath))
|
|
2714
|
+
continue;
|
|
2715
|
+
try {
|
|
2716
|
+
const html = fs.readFileSync(path.join(rootPath, focusPath), 'utf8');
|
|
2717
|
+
const linkedAssets = this.extractLinkedFrontendAssets(html, focusPath);
|
|
2718
|
+
for (const assetPath of [...linkedAssets.assets, ...linkedAssets.css, ...linkedAssets.js]) {
|
|
2719
|
+
if (candidatePaths.includes(assetPath) && !linkedFocusAssets.includes(assetPath)) {
|
|
2720
|
+
linkedFocusAssets.push(assetPath);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
catch {
|
|
2725
|
+
// Best effort: the explicit target remains in focusFiles.
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
const hydrationFocusFiles = [...focusFiles, ...linkedFocusAssets];
|
|
2660
2729
|
const agentStatePaths = this.collectAgentStateSyncPaths(rootPath);
|
|
2661
|
-
let orderedPaths = [...agentStatePaths, ...candidatePaths];
|
|
2730
|
+
let orderedPaths = [...agentStatePaths, ...hydrationFocusFiles, ...candidatePaths];
|
|
2662
2731
|
try {
|
|
2663
2732
|
const ranked = buildSemanticContext(rootPath, requestFocus, 60).topFiles.map((file) => file.path);
|
|
2664
2733
|
const changes = getChangedFiles(rootPath, candidatePaths);
|
|
@@ -2670,6 +2739,8 @@ menu {
|
|
|
2670
2739
|
// silently dropped progress.json and forced /continue to re-plan.
|
|
2671
2740
|
for (const filePath of agentStatePaths)
|
|
2672
2741
|
ordered.add(filePath);
|
|
2742
|
+
for (const filePath of hydrationFocusFiles)
|
|
2743
|
+
ordered.add(filePath);
|
|
2673
2744
|
for (const filePath of changes.changed)
|
|
2674
2745
|
ordered.add(filePath);
|
|
2675
2746
|
for (const filePath of ranked)
|
|
@@ -2685,9 +2756,11 @@ menu {
|
|
|
2685
2756
|
};
|
|
2686
2757
|
}
|
|
2687
2758
|
catch {
|
|
2688
|
-
orderedPaths = [...agentStatePaths, ...candidatePaths];
|
|
2759
|
+
orderedPaths = [...agentStatePaths, ...hydrationFocusFiles, ...candidatePaths];
|
|
2689
2760
|
}
|
|
2690
2761
|
summary.fileCount = snapshot.fileCount;
|
|
2762
|
+
summary.focusFiles = hydrationFocusFiles;
|
|
2763
|
+
summary.explicitFocusFiles = focusFiles;
|
|
2691
2764
|
summary.files = orderedPaths.slice(0, 40);
|
|
2692
2765
|
const packageJsonPath = path.join(rootPath, 'package.json');
|
|
2693
2766
|
if (fs.existsSync(packageJsonPath)) {
|
|
@@ -2714,6 +2787,21 @@ menu {
|
|
|
2714
2787
|
return null;
|
|
2715
2788
|
}
|
|
2716
2789
|
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Build complete workspace hydration separately from model context.
|
|
2792
|
+
* Context compaction must not become filesystem compaction.
|
|
2793
|
+
*/
|
|
2794
|
+
buildOutOfBandWorkspaceFiles(context) {
|
|
2795
|
+
const resolvedContext = this.ensureExecutionContext(context);
|
|
2796
|
+
const localWorkspacePath = this.resolveAgentTargetPath(resolvedContext);
|
|
2797
|
+
const serverWorkspacePath = this.resolveServerBindableWorkspacePath(resolvedContext);
|
|
2798
|
+
if (serverWorkspacePath || !localWorkspacePath)
|
|
2799
|
+
return undefined;
|
|
2800
|
+
const promptFocus = String(resolvedContext.rawPrompt || resolvedContext.contextualPrompt || resolvedContext.prompt || '');
|
|
2801
|
+
const summary = this.buildLocalWorkspaceSummary(localWorkspacePath, promptFocus);
|
|
2802
|
+
const files = summary?.workspaceFiles;
|
|
2803
|
+
return files && typeof files === 'object' ? files : undefined;
|
|
2804
|
+
}
|
|
2717
2805
|
/**
|
|
2718
2806
|
* Collect text file contents from the workspace for V3 agent hydration.
|
|
2719
2807
|
* Budget: up to ~2 MB total, per-file cap 200 KB, skip binary extensions.
|
|
@@ -2722,7 +2810,7 @@ menu {
|
|
|
2722
2810
|
const MAX_TOTAL_BYTES = 2 * 1024 * 1024;
|
|
2723
2811
|
const MAX_FILE_BYTES = 200 * 1024;
|
|
2724
2812
|
const BINARY_EXTENSIONS = new Set([
|
|
2725
|
-
'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.
|
|
2813
|
+
'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.webp', '.avif',
|
|
2726
2814
|
'.mp3', '.mp4', '.wav', '.ogg', '.webm', '.flac', '.aac',
|
|
2727
2815
|
'.zip', '.gz', '.tar', '.rar', '.7z', '.bz2',
|
|
2728
2816
|
'.exe', '.dll', '.so', '.dylib', '.bin', '.dat',
|
|
@@ -3028,7 +3116,9 @@ menu {
|
|
|
3028
3116
|
const args = event.arguments || {};
|
|
3029
3117
|
const serverRoot = String(context.__v3ServerWorkspaceRoot || '').trim();
|
|
3030
3118
|
const isRunCommand = name === 'run_command';
|
|
3031
|
-
const pathArg = isRunCommand
|
|
3119
|
+
const pathArg = isRunCommand
|
|
3120
|
+
? (args.cwd ?? args.path ?? args.directory ?? '.')
|
|
3121
|
+
: (args.path || args.directory || args.cwd || '.');
|
|
3032
3122
|
let target = this.resolveV3ClientToolPath(rootPath, pathArg, serverRoot ? [serverRoot] : []);
|
|
3033
3123
|
if (!target && isRunCommand) {
|
|
3034
3124
|
target = this.resolveV3ClientToolPath(rootPath, '.', serverRoot ? [serverRoot] : []);
|
|
@@ -4120,6 +4210,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4120
4210
|
const expectedFiles = this.extractExpectedWorkspaceFiles(message, executionContext);
|
|
4121
4211
|
const requestedModel = String(executionContext.model || executionContext.requestedModel || 'agent');
|
|
4122
4212
|
const resolvedModel = this.resolvePermittedModelId(requestedModel);
|
|
4213
|
+
const workspaceFiles = this.buildOutOfBandWorkspaceFiles(executionContext);
|
|
4123
4214
|
const preferLocalV3 = /(premium|polished|landing|site|page|dashboard|saas|frontend|ui|responsive|animated|create the required project files and write them to the workspace)/i.test(message)
|
|
4124
4215
|
&& context.localMachineCapable !== false;
|
|
4125
4216
|
const timeoutMs = resolvePlannerAgentTimeoutMs(baseTimeoutMs, String(executionContext.agentTaskType || ''), String(executionContext.rawPrompt || message || ''));
|
|
@@ -4149,7 +4240,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4149
4240
|
strict_mode: useRelaxedAttempt ? false : requestExecutionContext.legacyFallbackAllowed !== true,
|
|
4150
4241
|
context: useRelaxedAttempt
|
|
4151
4242
|
? this.buildMinimalV3AgentContext(requestExecutionContext)
|
|
4152
|
-
: this.buildV3AgentContext(requestExecutionContext),
|
|
4243
|
+
: this.buildV3AgentContext({ ...requestExecutionContext, workspaceFilesOutOfBand: !!workspaceFiles }),
|
|
4244
|
+
workspace_files: useRelaxedAttempt ? undefined : workspaceFiles,
|
|
4153
4245
|
context_id: contextIdOverride ?? requestExecutionContext.contextId,
|
|
4154
4246
|
mcp_context_id: useRelaxedAttempt ? null : requestExecutionContext.mcpContextId || null,
|
|
4155
4247
|
stream: true,
|
|
@@ -4364,18 +4456,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4364
4456
|
await this.ensureV3ServiceKey();
|
|
4365
4457
|
const executionContext = await this.bindExecutionContext({
|
|
4366
4458
|
...context,
|
|
4459
|
+
rawPrompt: context.rawPrompt || context.prompt || message,
|
|
4460
|
+
prompt: context.prompt || context.rawPrompt || message,
|
|
4367
4461
|
backgroundJob: true,
|
|
4368
4462
|
clientToolExecution: false,
|
|
4369
4463
|
});
|
|
4370
4464
|
const requestedModel = String(executionContext.model || executionContext.requestedModel || 'agent');
|
|
4371
4465
|
const resolvedModel = this.resolvePermittedModelId(requestedModel);
|
|
4466
|
+
const workspaceFiles = this.buildOutOfBandWorkspaceFiles(executionContext);
|
|
4372
4467
|
const body = {
|
|
4373
4468
|
request: message,
|
|
4374
4469
|
context: this.buildV3AgentContext({
|
|
4375
4470
|
...executionContext,
|
|
4376
4471
|
backgroundJob: true,
|
|
4377
4472
|
clientToolExecution: false,
|
|
4473
|
+
workspaceFilesOutOfBand: !!workspaceFiles,
|
|
4378
4474
|
}),
|
|
4475
|
+
workspace_files: workspaceFiles,
|
|
4379
4476
|
stream: false,
|
|
4380
4477
|
model: resolvedModel,
|
|
4381
4478
|
mcp_context_id: executionContext.mcpContextId || undefined,
|
|
@@ -4464,6 +4561,33 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4464
4561
|
}
|
|
4465
4562
|
throw new Error(`Unable to cancel background job: ${errors.join('; ')}`);
|
|
4466
4563
|
}
|
|
4564
|
+
async resolveV3BackgroundApproval(jobId, approvalId, approved, allowMode = 'once') {
|
|
4565
|
+
await this.ensureV3ServiceKey();
|
|
4566
|
+
const errors = [];
|
|
4567
|
+
for (const baseUrl of this.getV3AgentBaseUrls(false)) {
|
|
4568
|
+
try {
|
|
4569
|
+
const response = await fetch(this.getV3AgentApprovalUrl(baseUrl), {
|
|
4570
|
+
method: 'POST',
|
|
4571
|
+
headers: await this.getV3AgentHeaders(),
|
|
4572
|
+
body: JSON.stringify({
|
|
4573
|
+
context_id: jobId,
|
|
4574
|
+
approval_id: approvalId,
|
|
4575
|
+
approved,
|
|
4576
|
+
allow_mode: allowMode,
|
|
4577
|
+
}),
|
|
4578
|
+
});
|
|
4579
|
+
if (!response.ok) {
|
|
4580
|
+
errors.push(`${baseUrl}: ${response.status}`);
|
|
4581
|
+
continue;
|
|
4582
|
+
}
|
|
4583
|
+
return await response.json();
|
|
4584
|
+
}
|
|
4585
|
+
catch (error) {
|
|
4586
|
+
errors.push(`${baseUrl}: ${error?.message || String(error)}`);
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
throw new Error(`Unable to resolve background approval: ${errors.join('; ')}`);
|
|
4590
|
+
}
|
|
4467
4591
|
async getV3BackgroundJobFiles(jobId) {
|
|
4468
4592
|
await this.ensureV3ServiceKey();
|
|
4469
4593
|
const errors = [];
|
|
@@ -4486,7 +4610,45 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4486
4610
|
throw new Error(`Unable to fetch background job files: ${errors.join('; ')}`);
|
|
4487
4611
|
}
|
|
4488
4612
|
async applyV3BackgroundJobFiles(jobId, context = {}) {
|
|
4489
|
-
const data = await
|
|
4613
|
+
const [data, job] = await Promise.all([
|
|
4614
|
+
this.getV3BackgroundJobFiles(jobId),
|
|
4615
|
+
this.getV3BackgroundJob(jobId),
|
|
4616
|
+
]);
|
|
4617
|
+
if (job?.status !== 'completed' || job?.result?.success === false || job?.result?.type === 'error') {
|
|
4618
|
+
throw new Error(`Background job ${jobId} is not a successful completed job and cannot be applied.`);
|
|
4619
|
+
}
|
|
4620
|
+
const mutatedPaths = new Set();
|
|
4621
|
+
const addMutatedPath = (value) => {
|
|
4622
|
+
const normalized = this.normalizeWorkspaceRelativePath(String(value || ''));
|
|
4623
|
+
if (!normalized || path.isAbsolute(normalized) || normalized.split('/').includes('..'))
|
|
4624
|
+
return;
|
|
4625
|
+
mutatedPaths.add(normalized);
|
|
4626
|
+
};
|
|
4627
|
+
for (const filePath of (data.confirmed_mutations || []))
|
|
4628
|
+
addMutatedPath(filePath);
|
|
4629
|
+
for (const event of (Array.isArray(job?.events) ? job.events : [])) {
|
|
4630
|
+
if (event?.type === 'file_mutation' && event?.action !== 'delete')
|
|
4631
|
+
addMutatedPath(event.path);
|
|
4632
|
+
if (event?.type === 'executor_complete') {
|
|
4633
|
+
let summary = event.summary;
|
|
4634
|
+
if (typeof summary === 'string') {
|
|
4635
|
+
try {
|
|
4636
|
+
summary = JSON.parse(summary);
|
|
4637
|
+
}
|
|
4638
|
+
catch {
|
|
4639
|
+
summary = null;
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4642
|
+
if (summary?.status === 'completed') {
|
|
4643
|
+
for (const filePath of [...(summary.changed_files || []), ...(summary.created_files || [])]) {
|
|
4644
|
+
addMutatedPath(filePath);
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
if (mutatedPaths.size === 0) {
|
|
4650
|
+
throw new Error(`Background job ${jobId} has no confirmed successful file mutations to apply.`);
|
|
4651
|
+
}
|
|
4490
4652
|
const rootPath = this.resolveAgentTargetPath({
|
|
4491
4653
|
...context,
|
|
4492
4654
|
workspacePath: context.workspacePath || data.local_workspace_path,
|
|
@@ -4499,6 +4661,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4499
4661
|
const applied = [];
|
|
4500
4662
|
const skipped = [];
|
|
4501
4663
|
for (const [relativePath, content] of Object.entries(data.files || {})) {
|
|
4664
|
+
const normalizedRelativePath = this.normalizeWorkspaceRelativePath(relativePath);
|
|
4665
|
+
if (!mutatedPaths.has(normalizedRelativePath)) {
|
|
4666
|
+
skipped.push(relativePath);
|
|
4667
|
+
continue;
|
|
4668
|
+
}
|
|
4502
4669
|
if (typeof content !== 'string') {
|
|
4503
4670
|
skipped.push(relativePath);
|
|
4504
4671
|
continue;
|
|
@@ -4924,7 +5091,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4924
5091
|
'vigthoria-cloud-ultra',
|
|
4925
5092
|
]);
|
|
4926
5093
|
if (cloudModels.has(resolvedModel)) {
|
|
4927
|
-
return '
|
|
5094
|
+
return 'Vigthoria-v4-Code-27B';
|
|
4928
5095
|
}
|
|
4929
5096
|
return null;
|
|
4930
5097
|
}
|
|
@@ -4940,10 +5107,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4940
5107
|
}
|
|
4941
5108
|
resolvePermittedModelId(shortName) {
|
|
4942
5109
|
const normalizedRequested = String(shortName || '').trim().toLowerCase();
|
|
4943
|
-
const blockedModels = new Set(['
|
|
5110
|
+
const blockedModels = new Set(['mini', 'creative-v3', 'creative-v4']);
|
|
4944
5111
|
if (blockedModels.has(normalizedRequested)) {
|
|
4945
|
-
this.logger.debug(`Blocked
|
|
4946
|
-
return '
|
|
5112
|
+
this.logger.debug(`Blocked retired model ${shortName}; using fallback Vigthoria-v4-Code-27B`);
|
|
5113
|
+
return 'Vigthoria-v4-Code-27B';
|
|
4947
5114
|
}
|
|
4948
5115
|
const resolvedModel = this.resolveModelId(shortName);
|
|
4949
5116
|
if (this.isCloudModelId(resolvedModel) && !this.canUseCloudModel()) {
|
|
@@ -4969,6 +5136,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4969
5136
|
isSelfHostedPreferredModel(resolvedModel, requestedModel) {
|
|
4970
5137
|
const normalizedRequested = String(requestedModel || '').toLowerCase();
|
|
4971
5138
|
const selfHostedModels = new Set([
|
|
5139
|
+
'Vigthoria-v4-Creative-27B',
|
|
5140
|
+
'Vigthoria-v4-Code-27B',
|
|
5141
|
+
'Vigthoria-v4-Assistant-9B',
|
|
4972
5142
|
'vigthoria-v3-code-35b',
|
|
4973
5143
|
'vigthoria-v3-code-35b:latest',
|
|
4974
5144
|
'vigthoria-v3-code-9b',
|
|
@@ -4979,6 +5149,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4979
5149
|
]);
|
|
4980
5150
|
return selfHostedModels.has(resolvedModel)
|
|
4981
5151
|
|| normalizedRequested === 'agent'
|
|
5152
|
+
|| normalizedRequested === 'architect'
|
|
5153
|
+
|| normalizedRequested === 'assistant'
|
|
4982
5154
|
|| normalizedRequested === 'code'
|
|
4983
5155
|
|| normalizedRequested === 'code-30b'
|
|
4984
5156
|
|| normalizedRequested === 'code-35b'
|
|
@@ -4989,9 +5161,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
4989
5161
|
}
|
|
4990
5162
|
getSelfHostedFallbackModelId(resolvedModel, requestedModel) {
|
|
4991
5163
|
if (this.isSelfHostedPreferredModel(resolvedModel, requestedModel)) {
|
|
4992
|
-
return resolvedModel === 'qwen3-coder:latest' ? '
|
|
5164
|
+
return resolvedModel === 'qwen3-coder:latest' ? 'Vigthoria-v4-Code-27B' : resolvedModel;
|
|
4993
5165
|
}
|
|
4994
|
-
return '
|
|
5166
|
+
return 'Vigthoria-v4-Code-27B';
|
|
4995
5167
|
}
|
|
4996
5168
|
// Streaming chat
|
|
4997
5169
|
async *chatStream(messages, model) {
|
|
@@ -5074,7 +5246,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5074
5246
|
// (/v1/chat/completions on api.vigthoria.io) which is the only
|
|
5075
5247
|
// backend that reliably accepts our auth token.
|
|
5076
5248
|
async chatComplete(systemPrompt, userPrompt, model, maxTokens) {
|
|
5077
|
-
const resolvedModel = model ? this.resolvePermittedModelId(model) : '
|
|
5249
|
+
const resolvedModel = model ? this.resolvePermittedModelId(model) : 'Vigthoria-v4-Code-27B';
|
|
5078
5250
|
const response = await this.modelRouterClient.post('/v1/chat/completions', {
|
|
5079
5251
|
model: resolvedModel,
|
|
5080
5252
|
messages: [
|
|
@@ -5924,21 +6096,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5924
6096
|
// ═══════════════════════════════════════════════════════════════
|
|
5925
6097
|
// Vigthoria server infrastructure models
|
|
5926
6098
|
// ═══════════════════════════════════════════════════════════════
|
|
5927
|
-
'fast': '
|
|
6099
|
+
'fast': 'Vigthoria-v4-Assistant-9B',
|
|
5928
6100
|
'mini': 'vigthoria-mini-0.6b',
|
|
5929
|
-
'balanced': '
|
|
5930
|
-
'balanced-4b': '
|
|
5931
|
-
'
|
|
6101
|
+
'balanced': 'Vigthoria-v4-Assistant-9B',
|
|
6102
|
+
'balanced-4b': 'Vigthoria-v4-Assistant-9B',
|
|
6103
|
+
'assistant': 'Vigthoria-v4-Assistant-9B',
|
|
6104
|
+
'creative': 'Vigthoria-v4-Creative-27B',
|
|
6105
|
+
'architect': 'Vigthoria-v4-Creative-27B',
|
|
5932
6106
|
// Code Models - 35B is the default powerhouse
|
|
5933
|
-
'code': '
|
|
5934
|
-
'code-30b': '
|
|
5935
|
-
'code-35b': '
|
|
5936
|
-
'code-8b': '
|
|
5937
|
-
'code-9b': '
|
|
5938
|
-
'pro': '
|
|
5939
|
-
'agent': '
|
|
5940
|
-
'vigthoria-code': '
|
|
5941
|
-
'vigthoria-agent': '
|
|
6107
|
+
'code': 'Vigthoria-v4-Code-27B',
|
|
6108
|
+
'code-30b': 'Vigthoria-v4-Code-27B',
|
|
6109
|
+
'code-35b': 'Vigthoria-v4-Code-27B',
|
|
6110
|
+
'code-8b': 'Vigthoria-v4-Assistant-9B',
|
|
6111
|
+
'code-9b': 'Vigthoria-v4-Assistant-9B',
|
|
6112
|
+
'pro': 'Vigthoria-v4-Code-27B',
|
|
6113
|
+
'agent': 'Vigthoria-v4-Code-27B',
|
|
6114
|
+
'vigthoria-code': 'Vigthoria-v4-Code-27B',
|
|
6115
|
+
'vigthoria-agent': 'Vigthoria-v4-Code-27B',
|
|
5942
6116
|
// ═══════════════════════════════════════════════════════════════
|
|
5943
6117
|
// VIGTHORIA CLOUD - current billing catalog aliases
|
|
5944
6118
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -5956,17 +6130,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
5956
6130
|
'cloud-ultra': 'vigthoria-cloud-maximum',
|
|
5957
6131
|
};
|
|
5958
6132
|
// If already a full model ID, return as-is
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
6133
|
+
const normalizedShortName = String(shortName || '').toLowerCase();
|
|
6134
|
+
if (normalizedShortName.includes('vigthoria') || shortName.includes('/') || shortName.includes(':')) {
|
|
6135
|
+
if (modelMap[normalizedShortName]) {
|
|
6136
|
+
return modelMap[normalizedShortName];
|
|
5962
6137
|
}
|
|
5963
6138
|
return shortName;
|
|
5964
6139
|
}
|
|
5965
|
-
return modelMap[
|
|
6140
|
+
return modelMap[normalizedShortName] || 'Vigthoria-v4-Code-27B';
|
|
5966
6141
|
}
|
|
5967
6142
|
async getCoderHealth() {
|
|
5968
6143
|
try {
|
|
5969
|
-
const response = await this.client.get('/api/health', { timeout:
|
|
6144
|
+
const response = await this.client.get('/api/health', { timeout: 12000 });
|
|
5970
6145
|
const ok = response.data?.status === 'ok' || response.data?.healthy === true;
|
|
5971
6146
|
return {
|
|
5972
6147
|
name: 'Coder API',
|
|
@@ -6141,7 +6316,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6141
6316
|
const candidates = ['/v1/models', '/models', '/api/models', '/api/tags'];
|
|
6142
6317
|
for (const endpoint of candidates) {
|
|
6143
6318
|
try {
|
|
6144
|
-
const response = await client.get(endpoint, { timeout:
|
|
6319
|
+
const response = await client.get(endpoint, { timeout: 12000 });
|
|
6145
6320
|
const modelCount = this.extractModelCount(response.data);
|
|
6146
6321
|
if (modelCount > 0) {
|
|
6147
6322
|
return { modelCount, endpoint };
|
|
@@ -6157,7 +6332,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6157
6332
|
const modelsApiUrl = this.config.get('modelsApiUrl');
|
|
6158
6333
|
try {
|
|
6159
6334
|
const [healthResponse, modelProbe] = await Promise.all([
|
|
6160
|
-
this.modelRouterClient.get('/health', { timeout:
|
|
6335
|
+
this.modelRouterClient.get('/health', { timeout: 12000 }),
|
|
6161
6336
|
this.probeModelList(this.modelRouterClient),
|
|
6162
6337
|
]);
|
|
6163
6338
|
const healthOk = this.isHealthyServicePayload(healthResponse.data);
|
|
@@ -6190,7 +6365,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6190
6365
|
}
|
|
6191
6366
|
try {
|
|
6192
6367
|
const [healthResponse, modelProbe] = await Promise.all([
|
|
6193
|
-
this.selfHostedModelRouterClient.get('/health', { timeout:
|
|
6368
|
+
this.selfHostedModelRouterClient.get('/health', { timeout: 12000 }),
|
|
6194
6369
|
this.probeModelList(this.selfHostedModelRouterClient),
|
|
6195
6370
|
]);
|
|
6196
6371
|
const healthOk = this.isHealthyServicePayload(healthResponse.data);
|
|
@@ -6228,7 +6403,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6228
6403
|
for (const endpoint of candidates) {
|
|
6229
6404
|
try {
|
|
6230
6405
|
const controller = new AbortController();
|
|
6231
|
-
const timer = setTimeout(() => controller.abort(),
|
|
6406
|
+
const timer = setTimeout(() => controller.abort(), 12000);
|
|
6232
6407
|
const response = await fetch(endpoint, {
|
|
6233
6408
|
method: 'GET',
|
|
6234
6409
|
headers,
|
|
@@ -6303,9 +6478,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6303
6478
|
const endpoint = process.env.VIGTHORIA_HYPERLOOP_URL || `${configuredApiUrl}/api/hyperloop/health`;
|
|
6304
6479
|
try {
|
|
6305
6480
|
const token = this.getAccessToken();
|
|
6481
|
+
const hyperLoopServiceKey = process.env.VIGTHORIA_HYPERLOOP_SERVICE_KEY || process.env.HYPERLOOP_SERVICE_KEY || '';
|
|
6306
6482
|
const response = await fetchWithServiceTimeout(endpoint, {
|
|
6307
6483
|
method: 'GET',
|
|
6308
|
-
headers:
|
|
6484
|
+
headers: {
|
|
6485
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6486
|
+
...(hyperLoopServiceKey ? { 'X-Service-Key': hyperLoopServiceKey } : {}),
|
|
6487
|
+
},
|
|
6309
6488
|
});
|
|
6310
6489
|
if (!response.ok) {
|
|
6311
6490
|
throw new Error(`Hyper Loop health ${response.status}`);
|
|
@@ -6333,13 +6512,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6333
6512
|
const endpoint = process.env.VIGTHORIA_HYPERLOOP_EXECUTE_URL || `${configuredApiUrl}/api/hyperloop/execute`;
|
|
6334
6513
|
const modulesEndpoint = process.env.VIGTHORIA_HYPERLOOP_MODULES_URL || `${configuredApiUrl}/api/hyperloop/modules`;
|
|
6335
6514
|
const token = this.getAccessToken();
|
|
6515
|
+
const hyperLoopServiceKey = process.env.VIGTHORIA_HYPERLOOP_SERVICE_KEY || process.env.HYPERLOOP_SERVICE_KEY || '';
|
|
6516
|
+
const hyperLoopHeaders = {
|
|
6517
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6518
|
+
...(hyperLoopServiceKey ? { 'X-Service-Key': hyperLoopServiceKey } : {}),
|
|
6519
|
+
};
|
|
6336
6520
|
const projectPath = this.resolveAgentTargetPath(context);
|
|
6337
6521
|
try {
|
|
6338
6522
|
const modulesResponse = await fetchWithServiceTimeout(modulesEndpoint, {
|
|
6339
6523
|
method: 'GET',
|
|
6340
|
-
headers:
|
|
6341
|
-
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6342
|
-
},
|
|
6524
|
+
headers: hyperLoopHeaders,
|
|
6343
6525
|
});
|
|
6344
6526
|
if (!modulesResponse.ok) {
|
|
6345
6527
|
throw new Error(`Repo memory modules ${modulesResponse.status}`);
|
|
@@ -6351,10 +6533,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6351
6533
|
try {
|
|
6352
6534
|
const probeResponse = await fetchWithServiceTimeout(endpoint, {
|
|
6353
6535
|
method: 'POST',
|
|
6354
|
-
headers: {
|
|
6355
|
-
'Content-Type': 'application/json',
|
|
6356
|
-
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
6357
|
-
},
|
|
6536
|
+
headers: { 'Content-Type': 'application/json', ...hyperLoopHeaders },
|
|
6358
6537
|
body: JSON.stringify({
|
|
6359
6538
|
module: 'repo_context_compactor',
|
|
6360
6539
|
payload: {
|
|
@@ -6371,7 +6550,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6371
6550
|
});
|
|
6372
6551
|
if (probeResponse.ok) {
|
|
6373
6552
|
const probeData = await probeResponse.json();
|
|
6374
|
-
compactContextLength = String(probeData?.result?.compact_context
|
|
6553
|
+
compactContextLength = String(probeData?.result?.compact_context
|
|
6554
|
+
|| probeData?.result?.result?.compact_context
|
|
6555
|
+
|| '').length;
|
|
6375
6556
|
}
|
|
6376
6557
|
}
|
|
6377
6558
|
catch {
|
|
@@ -6488,12 +6669,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
6488
6669
|
});
|
|
6489
6670
|
}
|
|
6490
6671
|
async getCapabilityTruthStatus(context = {}) {
|
|
6491
|
-
//
|
|
6492
|
-
//
|
|
6493
|
-
//
|
|
6672
|
+
// The public edge can legitimately take 5-10 seconds during cold routing.
|
|
6673
|
+
// Keep a finite ceiling, but do not turn a healthy slow edge into the old
|
|
6674
|
+
// hard 10-second preflight failure seen on external client machines.
|
|
6494
6675
|
const withTimeout = (p, name) => Promise.race([
|
|
6495
6676
|
p,
|
|
6496
|
-
new Promise(resolve => setTimeout(() => resolve({ name, endpoint: '', ok: false, error: 'Service not reachable (
|
|
6677
|
+
new Promise(resolve => setTimeout(() => resolve({ name, endpoint: '', ok: false, error: 'Service not reachable (15 s timeout)' }), 15000)),
|
|
6497
6678
|
]);
|
|
6498
6679
|
const [v3Agent, hyperLoop, repoMemory, devtoolsBridge] = await Promise.all([
|
|
6499
6680
|
withTimeout(this.getV3AgentHealth(), 'V3 Agent'),
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
export type ClientManifestPayload = {
|
|
2
2
|
product_id: string;
|
|
3
|
+
context_contract_version: string;
|
|
4
|
+
source_product_id: string;
|
|
5
|
+
active_application_id: string;
|
|
6
|
+
active_surface_id: string;
|
|
7
|
+
target_product_id: string;
|
|
8
|
+
workspace_kind: string;
|
|
9
|
+
selected_engine_id: string;
|
|
10
|
+
capability_catalog_version: string;
|
|
11
|
+
capability_scope_id: string;
|
|
3
12
|
version: string;
|
|
4
13
|
os: string;
|
|
5
14
|
execution_mode: string;
|