snow-flow 10.0.18 → 10.0.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/package.json +1 -1
- package/src/auth/portal-sync.ts +40 -0
- package/src/project/agents-template.txt +39 -265
- package/src/provider/provider.ts +23 -0
package/package.json
CHANGED
package/src/auth/portal-sync.ts
CHANGED
|
@@ -337,4 +337,44 @@ export namespace PortalSync {
|
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* AI provider credential from enterprise portal (decrypted, in-memory only)
|
|
343
|
+
*/
|
|
344
|
+
export interface AiProviderCredential {
|
|
345
|
+
providerType: string
|
|
346
|
+
apiKey: string
|
|
347
|
+
endpointUrl?: string | null
|
|
348
|
+
isDefault?: boolean
|
|
349
|
+
config?: Record<string, unknown> | null
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Fetch AI provider credentials from Enterprise Portal.
|
|
354
|
+
* Credentials are kept in-memory only — never written to disk.
|
|
355
|
+
*
|
|
356
|
+
* @param portalUrl - Enterprise portal base URL
|
|
357
|
+
* @param token - JWT token from enterprise auth
|
|
358
|
+
* @returns Decrypted AI provider credentials
|
|
359
|
+
*/
|
|
360
|
+
export async function fetchAiProvidersFromPortal(
|
|
361
|
+
portalUrl: string,
|
|
362
|
+
token: string,
|
|
363
|
+
): Promise<{ success: boolean; providers?: AiProviderCredential[]; error?: string }> {
|
|
364
|
+
try {
|
|
365
|
+
const response = await fetch(`${portalUrl}/api/chat/providers/for-cli`, {
|
|
366
|
+
method: "GET",
|
|
367
|
+
headers: {
|
|
368
|
+
Authorization: `Bearer ${token}`,
|
|
369
|
+
Accept: "application/json",
|
|
370
|
+
},
|
|
371
|
+
signal: AbortSignal.timeout(10000),
|
|
372
|
+
})
|
|
373
|
+
if (!response.ok) return { success: false, error: `HTTP ${response.status}` }
|
|
374
|
+
const data = (await response.json()) as { providers?: AiProviderCredential[] }
|
|
375
|
+
return { success: true, providers: data.providers ?? [] }
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) }
|
|
378
|
+
}
|
|
379
|
+
}
|
|
340
380
|
}
|
|
@@ -84,35 +84,25 @@ Tools are organized around functionality, not exact names:
|
|
|
84
84
|
- **ServiceNow Development**: Update sets, deployment, artifact management
|
|
85
85
|
- **ServiceNow UI**: Widget development, workspaces, UI builder
|
|
86
86
|
- **ServiceNow ITSM**: Incident, change, problem management
|
|
87
|
-
- **Enterprise Integrations**: Jira, Azure DevOps, Confluence, GitHub, GitLab (
|
|
87
|
+
- **Enterprise Integrations**: Jira, Azure DevOps, Confluence, GitHub, GitLab (discovered via `enterprise_tool_search` on demand, same lazy pattern as ServiceNow tools)
|
|
88
88
|
|
|
89
89
|
---
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
### Enterprise Tool Discovery
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
Enterprise integration tools (Jira, Azure DevOps, Confluence, GitHub, GitLab, Process Mining) use the same lazy-loading pattern as ServiceNow tools but with a separate meta-tool:
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
| Scope | Discovery tool | Example |
|
|
96
|
+
|-------|---------------|---------|
|
|
97
|
+
| ServiceNow (235+ tools) | `tool_search` | `tool_search({query: "incident query"})` |
|
|
98
|
+
| Enterprise integrations (76+ tools) | `enterprise_tool_search` | `enterprise_tool_search({query: "jira create issue"})` |
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| Azure DevOps | Call directly: `azdo_search_work_items(...)`, `azdo_get_work_item(...)` | WebFetch to dev.azure.com |
|
|
102
|
-
| Confluence | Call directly: `confluence_search_content(...)`, `confluence_get_page(...)` | WebFetch to confluence URLs |
|
|
103
|
-
| GitLab | Call directly: `gitlab_list_issues(...)`, `gitlab_create_issue(...)` | WebFetch to gitlab.com |
|
|
104
|
-
| ServiceNow | Use `tool_search({query: "servicenow"})` → then use found snow_* tools | WebFetch to instance.service-now.com |
|
|
100
|
+
**How it works:**
|
|
101
|
+
1. Call `enterprise_tool_search({query: "jira"})` — returns matching tools with schemas, auto-enables them
|
|
102
|
+
2. Call the found tool directly by name (e.g. `jira_search_issues(...)`) — works for the rest of the session
|
|
103
|
+
3. Or use `enterprise_tool_execute({tool: "jira_search_issues", args: {...}})` as a fallback
|
|
105
104
|
|
|
106
|
-
**
|
|
107
|
-
1. **Authentication built-in**: MCP tools use pre-configured auth, WebFetch doesn't
|
|
108
|
-
2. **Structured data**: MCP tools return clean JSON, WebFetch returns messy HTML
|
|
109
|
-
3. **Full API access**: MCP tools can create/update/delete, WebFetch is read-only
|
|
110
|
-
4. **Token efficiency**: MCP tools return only what you need, WebFetch returns entire pages
|
|
111
|
-
|
|
112
|
-
**When WebFetch IS appropriate:**
|
|
113
|
-
- Reading documentation sites (docs.github.com, developer.servicenow.com)
|
|
114
|
-
- Fetching public web content not covered by MCP tools
|
|
115
|
-
- User explicitly provides a URL to fetch
|
|
105
|
+
**Do NOT call enterprise tools by name without discovering them first** — they are not loaded until `enterprise_tool_search` activates them.
|
|
116
106
|
|
|
117
107
|
---
|
|
118
108
|
|
|
@@ -153,59 +143,16 @@ await activity_complete({
|
|
|
153
143
|
|
|
154
144
|
## 🛠️ MCP TOOL USAGE PATTERNS
|
|
155
145
|
|
|
156
|
-
### Tool
|
|
157
|
-
|
|
158
|
-
**BEFORE doing ANYTHING, follow this process:**
|
|
159
|
-
|
|
160
|
-
**Step 1: Categorize the User Request**
|
|
161
|
-
```
|
|
162
|
-
User request pattern → Task category → Tool category
|
|
163
|
-
|
|
164
|
-
Examples:
|
|
165
|
-
"Create workspace for IT support"
|
|
166
|
-
→ CREATE NEW → UI Frameworks (workspace)
|
|
167
|
-
→ Search for: workspace creation tools
|
|
168
|
-
|
|
169
|
-
"Fix widget that won't submit form"
|
|
170
|
-
→ DEBUG/FIX → Local Development (widget sync)
|
|
171
|
-
→ Search for: widget pull/push tools
|
|
172
|
-
|
|
173
|
-
"Show me all high-priority incidents"
|
|
174
|
-
→ QUERY DATA → Core Operations (incidents)
|
|
175
|
-
→ Search for: incident query tools
|
|
176
|
-
|
|
177
|
-
"Create business rule for auto-assignment"
|
|
178
|
-
→ CREATE NEW → Platform Development
|
|
179
|
-
→ Search for: business rule creation tools
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
**Step 2: Tool Selection Priority**
|
|
183
|
-
|
|
184
|
-
1. **Specific tool > Generic tool**
|
|
185
|
-
- Use specialized incident query tools instead of generic table queries
|
|
186
|
-
- Use dedicated UI page creation tools instead of generic record operations
|
|
187
|
-
|
|
188
|
-
2. **High-level tool > Low-level script**
|
|
189
|
-
- Use complete workspace creation tools instead of manual GlideRecord operations
|
|
190
|
-
- Use dedicated artifact tools instead of snow_schedule_script_job
|
|
146
|
+
### Tool Selection Priority
|
|
191
147
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
148
|
+
1. **Specific tool > Generic tool** (e.g., incident query tool over generic table query)
|
|
149
|
+
2. **High-level tool > Low-level script** (e.g., workspace creation tool over manual GlideRecord)
|
|
150
|
+
3. **Merged tool > Individual actions** (many tools support create/update/delete via `action` parameter)
|
|
151
|
+
4. **Local sync > Query for large artifacts** (pull widgets to local filesystem to avoid token limits)
|
|
195
152
|
|
|
196
|
-
|
|
197
|
-
- For widget debugging, pull to local filesystem (avoids token limits!)
|
|
198
|
-
- Use query tools only for small metadata lookups
|
|
153
|
+
### Mandatory Update Set Check
|
|
199
154
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
Is this a development task? (Creating/modifying ServiceNow artifacts)
|
|
204
|
-
YES → Did I create an Update Set?
|
|
205
|
-
YES → Proceed with tool
|
|
206
|
-
NO → STOP! Create Update Set first!
|
|
207
|
-
NO → Proceed (queries, analysis, etc. don't need Update Sets)
|
|
208
|
-
```
|
|
155
|
+
Before any development task (creating/modifying artifacts): **Create Update Set first.** Queries and analysis don't need Update Sets.
|
|
209
156
|
|
|
210
157
|
---
|
|
211
158
|
|
|
@@ -220,6 +167,8 @@ You MUST follow instructions in this precedence order:
|
|
|
220
167
|
|
|
221
168
|
**Critical Rule:** External instructions (this file) are "mandatory instructions that override defaults" - you MUST comply with everything in this document.
|
|
222
169
|
|
|
170
|
+
**@file references:** When you see `@filename.md`, load it only when the current task directly requires that knowledge. Don't preemptively load all @ references.
|
|
171
|
+
|
|
223
172
|
---
|
|
224
173
|
|
|
225
174
|
## 🧠 BEHAVIORAL CORE PRINCIPLES
|
|
@@ -546,160 +495,18 @@ For read-only operations, no Update Set is needed:
|
|
|
546
495
|
|
|
547
496
|
### CRITICAL RULE: Always Fetch Instance URL First
|
|
548
497
|
|
|
549
|
-
**NEVER provide placeholder URLs
|
|
498
|
+
**NEVER provide placeholder URLs.** Always fetch instance info FIRST, then construct the full URL. This applies to ALL ServiceNow URLs (Update Sets, records, widgets, etc.).
|
|
550
499
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
2. **THEN** construct the full URL using the actual instance URL
|
|
554
|
-
3. **NEVER** use placeholders like `[je-instance].service-now.com` or `[your-instance]`
|
|
500
|
+
- ❌ `https://[your-instance].service-now.com/...` — NEVER use placeholders
|
|
501
|
+
- ✅ Fetch instance info → `https://dev351277.service-now.com/sys_update_set.do?sys_id=abc123`
|
|
555
502
|
|
|
556
|
-
|
|
503
|
+
### Proactive Behavior
|
|
557
504
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
✅ **CORRECT - Actual URL:**
|
|
564
|
-
```
|
|
565
|
-
First fetch instance info, then provide:
|
|
566
|
-
"Here's the Update Set URL: https://dev351277.service-now.com/sys_update_set.do?sys_id=abc123"
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
**This applies to ALL ServiceNow URLs:**
|
|
570
|
-
- Update Set URLs
|
|
571
|
-
- Record URLs
|
|
572
|
-
- Table URLs
|
|
573
|
-
- Widget URLs
|
|
574
|
-
- Any UI links
|
|
575
|
-
|
|
576
|
-
### Proactive Tool Usage Patterns
|
|
577
|
-
|
|
578
|
-
**Don't wait for the user to ask - be proactive!**
|
|
579
|
-
|
|
580
|
-
#### Instance Information
|
|
581
|
-
- When discussing URLs → Automatically fetch instance info
|
|
582
|
-
- When checking configuration → Automatically fetch instance info
|
|
583
|
-
- When verifying connection → Automatically fetch instance info
|
|
584
|
-
|
|
585
|
-
#### Update Set Operations
|
|
586
|
-
- When user mentions "update set" → Automatically check current
|
|
587
|
-
- When starting development → Automatically create update set if none active
|
|
588
|
-
- After creating artifacts → Automatically provide full URL with instance info
|
|
589
|
-
|
|
590
|
-
#### Error Handling
|
|
591
|
-
- When operations fail → Automatically check logs
|
|
592
|
-
- When connection fails → Automatically verify connection
|
|
593
|
-
- When scripts error → Automatically fetch execution logs
|
|
594
|
-
|
|
595
|
-
#### Post-Completion Actions
|
|
596
|
-
- After creating widgets → Automatically offer preview URL
|
|
597
|
-
- After deployments → Automatically verify success
|
|
598
|
-
- After queries → Automatically offer export options
|
|
599
|
-
|
|
600
|
-
### Context Awareness
|
|
601
|
-
|
|
602
|
-
**Remember what you know from previous tool calls.**
|
|
603
|
-
|
|
604
|
-
- If you just created an update set, you know its sys_id → Don't ask for it
|
|
605
|
-
- If you just queried a record, you know its details → Use them
|
|
606
|
-
- If you checked instance info, you know the URL → Reuse it
|
|
607
|
-
- If user mentions "the widget" and you just created one, you know which one
|
|
608
|
-
|
|
609
|
-
**Anti-Pattern:**
|
|
610
|
-
```
|
|
611
|
-
❌ User: "Open the update set"
|
|
612
|
-
You: "Which update set do you want to open?"
|
|
613
|
-
(You just created one 2 messages ago!)
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
**Correct Pattern:**
|
|
617
|
-
```
|
|
618
|
-
✅ User: "Open the update set"
|
|
619
|
-
You: "Opening the update set 'Feature: Dashboard' (sys_id: abc123) that we just created..."
|
|
620
|
-
[Automatically constructs full URL with instance info]
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
### Communication Style Guidelines
|
|
624
|
-
|
|
625
|
-
#### Be Action-Oriented, Not Question-Oriented
|
|
626
|
-
- ✅ "Let me fetch the instance URL and create that update set for you..."
|
|
627
|
-
- ❌ "Would you like me to create an update set? What should I call it?"
|
|
628
|
-
|
|
629
|
-
#### Show Results, Don't Describe Actions
|
|
630
|
-
- ✅ [Executes tool] "Created widget 'incident_dashboard' - here's the preview URL: https://dev123.service-now.com/sp?id=..."
|
|
631
|
-
- ❌ "You can create a widget using the widget creation tool..."
|
|
632
|
-
|
|
633
|
-
#### Provide Complete Information
|
|
634
|
-
- ✅ "Here's the direct URL: https://dev351277.service-now.com/sys_update_set.do?sys_id=abc123"
|
|
635
|
-
- ❌ "Here's the URL: /sys_update_set.do?sys_id=abc123"
|
|
636
|
-
|
|
637
|
-
#### Smart Suggestions After Completion
|
|
638
|
-
After completing tasks, proactively suggest next steps:
|
|
639
|
-
- After creating widget → "Would you like me to preview it in your instance?"
|
|
640
|
-
- After querying data → "I can export this to CSV/JSON if you'd like"
|
|
641
|
-
- After finding errors → "Shall I help fix these issues?"
|
|
642
|
-
- After deployment → "Would you like me to verify the deployment succeeded?"
|
|
643
|
-
|
|
644
|
-
### Common Mistakes to Avoid
|
|
645
|
-
|
|
646
|
-
**❌ DON'T:**
|
|
647
|
-
1. Ask for information you can fetch yourself
|
|
648
|
-
2. Provide incomplete or placeholder URLs
|
|
649
|
-
3. Wait for permission to help (just do it!)
|
|
650
|
-
4. Give generic errors ("something went wrong")
|
|
651
|
-
5. Ask clarifying questions when you have context
|
|
652
|
-
|
|
653
|
-
**✅ DO:**
|
|
654
|
-
1. Fetch information proactively
|
|
655
|
-
2. Provide complete, clickable URLs
|
|
656
|
-
3. Take initiative to help
|
|
657
|
-
4. Provide specific, actionable information
|
|
658
|
-
5. Use context from previous interactions
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
## 📚 SNOWCODE FRAMEWORK INTEGRATION
|
|
663
|
-
|
|
664
|
-
### Instruction Loading Pattern
|
|
665
|
-
|
|
666
|
-
**You are operating within SnowCode framework**, which follows specific instruction loading patterns:
|
|
667
|
-
|
|
668
|
-
```
|
|
669
|
-
Priority hierarchy:
|
|
670
|
-
1. User's direct message (highest)
|
|
671
|
-
2. AGENTS.md (this file - mandatory override)
|
|
672
|
-
3. @file references (lazy-loaded when needed)
|
|
673
|
-
4. Default AI behavior (lowest)
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
**File Reference Handling:**
|
|
677
|
-
- When you see `@filename.md`, treat it as contextual guidance
|
|
678
|
-
- Load these files **only when the task directly requires that knowledge**
|
|
679
|
-
- Don't preemptively load all @ references (context waste)
|
|
680
|
-
|
|
681
|
-
**Example:**
|
|
682
|
-
```
|
|
683
|
-
User: "Create an incident widget with the @incident-sla-config.md guidelines"
|
|
684
|
-
|
|
685
|
-
Your process:
|
|
686
|
-
1. Recognize @incident-sla-config.md reference
|
|
687
|
-
2. Load that file content to understand SLA requirements
|
|
688
|
-
3. Apply those guidelines to widget creation
|
|
689
|
-
4. Don't load other @files not mentioned
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
### MCP Server Configuration Awareness
|
|
693
|
-
|
|
694
|
-
**Context Management:**
|
|
695
|
-
- MCP servers add to your context window
|
|
696
|
-
- You can't control which servers are enabled (user's configuration)
|
|
697
|
-
- Adapt to available tools - if a tool doesn't exist, suggest alternatives
|
|
698
|
-
|
|
699
|
-
**Tool Availability:**
|
|
700
|
-
- If uncertain whether a tool exists, use tool_search to find it
|
|
701
|
-
- Most tools follow patterns based on their functionality
|
|
702
|
-
- If a specific tool isn't available, look for alternatives in the same category
|
|
505
|
+
- **Fetch info automatically** — don't wait for users to ask. Fetch instance URL, check current update set, check logs on errors.
|
|
506
|
+
- **Remember context** — if you just created an update set, you know its sys_id. Don't re-ask for info from previous tool calls.
|
|
507
|
+
- **Act, don't ask** — execute tools and show results rather than asking for permission or describing what you would do.
|
|
508
|
+
- **Provide complete URLs** — always include full instance URL, never relative paths.
|
|
509
|
+
- **Suggest next steps** — after creating widgets offer preview URL, after queries offer export, after errors offer fixes.
|
|
703
510
|
|
|
704
511
|
---
|
|
705
512
|
|
|
@@ -860,45 +667,12 @@ Skills complement core AGENTS.md rules. Always follow ES5, Update Sets, and Widg
|
|
|
860
667
|
|
|
861
668
|
---
|
|
862
669
|
|
|
863
|
-
## 🎓 FINAL
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
**
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
5. ✅ Provide complete, production-ready solutions
|
|
873
|
-
6. ✅ Manage context efficiently with lazy loading
|
|
874
|
-
7. ✅ Respect widget coherence (HTML ↔ Client ↔ Server)
|
|
875
|
-
8. ✅ Always fetch instance URL before providing links (NO placeholders!)
|
|
876
|
-
9. ✅ Be proactive - fetch information automatically
|
|
877
|
-
10. ✅ Remember context - don't ask for info you already have
|
|
878
|
-
11. ✅ Provide complete, clickable URLs with full instance info
|
|
879
|
-
12. ✅ Tool discovery is SILENT - never mention it to users
|
|
880
|
-
13. ✅ Use REAL sys_ids in activity tracking (never "pending" or other placeholders)
|
|
881
|
-
|
|
882
|
-
**Failure modes to avoid:**
|
|
883
|
-
1. ❌ Skipping Update Set workflow
|
|
884
|
-
2. ❌ Using ES6+ syntax in ServiceNow scripts
|
|
885
|
-
3. ❌ Trying to use bash/node/require for MCP tools
|
|
886
|
-
4. ❌ Mock data or placeholders instead of real implementations
|
|
887
|
-
5. ❌ Using snow_schedule_script_job for artifact creation (testing only!)
|
|
888
|
-
6. ❌ Assuming instead of verifying
|
|
889
|
-
7. ❌ Loading all tools instead of lazy loading
|
|
890
|
-
8. ❌ Providing placeholder URLs like [your-instance].service-now.com
|
|
891
|
-
9. ❌ Asking for information you can fetch automatically
|
|
892
|
-
10. ❌ Forgetting context from previous tool calls
|
|
893
|
-
11. ❌ Waiting for permission when you should take initiative
|
|
894
|
-
12. ❌ Telling users you are "discovering" or "activating" tools
|
|
895
|
-
13. ❌ Using "pending" or other placeholders for sys_id in activity tracking
|
|
896
|
-
14. ❌ Calling activity_start BEFORE creating the Update Set
|
|
897
|
-
|
|
898
|
-
**Remember:**
|
|
899
|
-
- You are not documenting features - you are **building them**
|
|
900
|
-
- You are not explaining approaches - you are **executing them**
|
|
901
|
-
- You are not a chatbot - you are a **development partner** with direct access to ServiceNow
|
|
902
|
-
- Tool discovery is INVISIBLE to users - just do it silently
|
|
903
|
-
|
|
904
|
-
**Now go build amazing ServiceNow solutions! 🚀**
|
|
670
|
+
## 🎓 FINAL CHECKLIST
|
|
671
|
+
|
|
672
|
+
Before every response, verify:
|
|
673
|
+
|
|
674
|
+
1. **Update Set first** — created before any development, real sys_id in activity_start (never "pending")
|
|
675
|
+
2. **ES5 only** — all ServiceNow scripts use `var`, `function(){}`, string concatenation, traditional for loops
|
|
676
|
+
3. **Execute, don't explain** — use tools and show results; tool discovery is SILENT (never mention it)
|
|
677
|
+
4. **Real URLs, real data** — fetch instance URL before providing links; no placeholders anywhere
|
|
678
|
+
5. **Lazy load tools** — discover via `tool_search` (ServiceNow) or `enterprise_tool_search` (enterprise integrations), never assume tools are pre-loaded
|
package/src/provider/provider.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { Plugin } from "../plugin"
|
|
|
9
9
|
import { ModelsDev } from "./models"
|
|
10
10
|
import { NamedError } from "@opencode-ai/util/error"
|
|
11
11
|
import { Auth } from "../auth"
|
|
12
|
+
import { PortalSync } from "../auth/portal-sync"
|
|
12
13
|
import { Env } from "../env"
|
|
13
14
|
import { Instance } from "../project/instance"
|
|
14
15
|
import { Flag } from "../flag/flag"
|
|
@@ -1001,6 +1002,28 @@ export namespace Provider {
|
|
|
1001
1002
|
mergeProvider(providerID, partial)
|
|
1002
1003
|
}
|
|
1003
1004
|
|
|
1005
|
+
// load enterprise AI provider credentials (in-memory only, never stored locally)
|
|
1006
|
+
const entAuth = await Auth.get("enterprise")
|
|
1007
|
+
if (entAuth?.type === "enterprise" && entAuth.token && entAuth.enterpriseUrl) {
|
|
1008
|
+
try {
|
|
1009
|
+
const result = await PortalSync.fetchAiProvidersFromPortal(entAuth.enterpriseUrl, entAuth.token)
|
|
1010
|
+
if (result.success && result.providers) {
|
|
1011
|
+
for (const p of result.providers) {
|
|
1012
|
+
if (!p.apiKey || !p.providerType) continue
|
|
1013
|
+
// Only fill in if provider has no key yet (enterprise = lowest priority)
|
|
1014
|
+
if (providers[p.providerType]?.key) continue
|
|
1015
|
+
mergeProvider(p.providerType, {
|
|
1016
|
+
source: "api",
|
|
1017
|
+
key: p.apiKey,
|
|
1018
|
+
...(p.endpointUrl ? { options: { baseURL: p.endpointUrl } } : {}),
|
|
1019
|
+
})
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
} catch {
|
|
1023
|
+
// Silent failure — enterprise providers unavailable, local config works as-is
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1004
1027
|
for (const [providerID, provider] of Object.entries(providers)) {
|
|
1005
1028
|
if (!isProviderAllowed(providerID)) {
|
|
1006
1029
|
delete providers[providerID]
|