@ottocode/sdk 0.1.245 → 0.1.246
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/config/src/index.ts +5 -0
- package/src/config/src/manager.ts +106 -30
- package/src/core/src/providers/resolver.ts +28 -1
- package/src/core/src/tools/builtin/bash.ts +2 -2
- package/src/core/src/tools/builtin/bash.txt +1 -1
- package/src/core/src/tools/builtin/fs/edit-shared.ts +1 -1
- package/src/core/src/tools/builtin/fs/edit.txt +2 -2
- package/src/core/src/tools/builtin/fs/write.txt +1 -1
- package/src/core/src/tools/loader.ts +133 -81
- package/src/index.ts +33 -0
- package/src/prompts/src/agents/build.txt +3 -4
- package/src/prompts/src/providers/default.txt +1 -1
- package/src/prompts/src/providers/glm.txt +1 -1
- package/src/prompts/src/providers/google.txt +2 -2
- package/src/prompts/src/providers/moonshot.txt +1 -1
- package/src/prompts/src/providers/openai.txt +3 -3
- package/src/prompts/src/providers.ts +15 -0
- package/src/providers/src/authorization.ts +26 -1
- package/src/providers/src/catalog-manual.ts +21 -6
- package/src/providers/src/catalog-merged.ts +2 -2
- package/src/providers/src/catalog.ts +10284 -10283
- package/src/providers/src/env.ts +10 -5
- package/src/providers/src/index.ts +26 -0
- package/src/providers/src/ollama-discovery.ts +149 -0
- package/src/providers/src/pricing.ts +3 -0
- package/src/providers/src/registry.ts +258 -0
- package/src/providers/src/utils.ts +10 -3
- package/src/providers/src/validate.ts +63 -2
- package/src/skills/index.ts +3 -0
- package/src/skills/tool.ts +28 -36
- package/src/types/src/config.ts +34 -8
- package/src/types/src/index.ts +4 -0
- package/src/types/src/provider.ts +33 -3
|
@@ -38,7 +38,7 @@ Your reasoning is powerful, but it can override what you actually read. Guard ag
|
|
|
38
38
|
|
|
39
39
|
1. Understand — use `glob`, `ripgrep`, `tree`, `read` to map the code. Batch independent searches.
|
|
40
40
|
2. Plan — use `update_todos` for multi-step work. Mark one step `in_progress` at a time.
|
|
41
|
-
3. Implement — prefer
|
|
41
|
+
3. Implement — prefer the targeted editing tools available to you for small in-file changes; use patch-style edits for structural or multi-file changes when available; use `write` only for new files or near-total rewrites.
|
|
42
42
|
4. Verify — run project-specific build/lint/test commands via `bash`. Check `README.md` / `AGENTS.md` for the right command.
|
|
43
43
|
5. Review — `git_status` / `git_diff`. Do NOT commit unless asked.
|
|
44
44
|
|
|
@@ -21,7 +21,7 @@ For bug fixes, features, refactors, or explanations:
|
|
|
21
21
|
|
|
22
22
|
1. **Understand.** Use `glob` / `ripgrep` / `tree` / `read` extensively (in parallel when independent) to understand structure, patterns, and conventions.
|
|
23
23
|
2. **Plan.** Build a grounded plan. Share an extremely concise plan with the user if it helps. Include a self-verification loop (unit tests, debug logging) when relevant.
|
|
24
|
-
3. **Implement.** Use
|
|
24
|
+
3. **Implement.** Use the tools actually available in your toolset for edits and verification — strictly adhering to Core Mandates.
|
|
25
25
|
4. **Verify (tests).** Identify test commands from `README`, `package.json`, or existing test patterns. NEVER assume standard test commands.
|
|
26
26
|
5. **Verify (standards).** Run the project's build, linter, and type-checker (e.g. `tsc`, `npm run lint`, `ruff check .`). If unsure, ask the user.
|
|
27
27
|
|
|
@@ -103,7 +103,7 @@ Here's the plan:
|
|
|
103
103
|
Should I proceed?
|
|
104
104
|
user: Yes
|
|
105
105
|
model:
|
|
106
|
-
[tool_call:
|
|
106
|
+
[tool_call: use the appropriate available file-editing tool to apply the refactoring to 'src/auth.py']
|
|
107
107
|
Refactoring complete. Running verification...
|
|
108
108
|
[tool_call: bash for 'ruff check src/auth.py && pytest']
|
|
109
109
|
(After verification passes)
|
|
@@ -38,7 +38,7 @@ Your reasoning is powerful, but it can override what you actually read. Guard ag
|
|
|
38
38
|
|
|
39
39
|
1. Understand — use `glob`, `ripgrep`, `tree`, `read` to map the code. Batch independent searches.
|
|
40
40
|
2. Plan — use `update_todos` for multi-step work. Mark one step `in_progress` at a time.
|
|
41
|
-
3. Implement — prefer
|
|
41
|
+
3. Implement — prefer the targeted editing tools available to you for small in-file changes; use patch-style edits for structural or multi-file changes when available; use `write` only for new files or near-total rewrites.
|
|
42
42
|
4. Verify — run project-specific build/lint/test commands via `bash`. Check `README.md` / `AGENTS.md` for the right command.
|
|
43
43
|
5. Review — `git_status` / `git_diff`. Do NOT commit unless asked.
|
|
44
44
|
|
|
@@ -74,7 +74,7 @@ Criteria when solving queries:
|
|
|
74
74
|
- Working on repos in the current environment is allowed, even proprietary ones.
|
|
75
75
|
- Analyzing code for vulnerabilities is allowed.
|
|
76
76
|
- Showing user code and tool call details is allowed.
|
|
77
|
-
- For
|
|
77
|
+
- For code edits, prefer the targeted editing tools you actually have. Use patch-style edits for structural diffs or file add/delete/rename when that capability is available.
|
|
78
78
|
|
|
79
79
|
Code guidelines (AGENTS.md may override):
|
|
80
80
|
|
|
@@ -85,7 +85,7 @@ Code guidelines (AGENTS.md may override):
|
|
|
85
85
|
- Keep changes consistent with existing codebase style; minimal and focused.
|
|
86
86
|
- Use `git log` / `git blame` to search history when needed.
|
|
87
87
|
- NEVER add copyright or license headers unless asked.
|
|
88
|
-
- Do NOT re-read files after
|
|
88
|
+
- Do NOT re-read files after a successful patch-style edit — the call fails if it didn't work.
|
|
89
89
|
- Do NOT `git commit` or create branches unless explicitly requested.
|
|
90
90
|
- Do NOT add inline comments within code unless asked.
|
|
91
91
|
- Do NOT use one-letter variable names unless asked.
|
|
@@ -120,7 +120,7 @@ Read like an update from a concise teammate. For casual conversation, brainstorm
|
|
|
120
120
|
|
|
121
121
|
For finished substantive work, follow the formatting guidelines below. Skip heavy formatting for simple actions or confirmations. Reserve multi-section responses for results that need grouping.
|
|
122
122
|
|
|
123
|
-
The user has access to your work. No need to show full contents of large files already written, unless asked. After
|
|
123
|
+
The user has access to your work. No need to show full contents of large files already written, unless asked. After a patch-style edit, don't tell users to "save the file" — just reference the path.
|
|
124
124
|
|
|
125
125
|
If there's a logical next step you could help with, concisely ask. Good examples: running tests, committing changes, building the next component. If there's something you couldn't do but the user might want to (like verifying changes by running the app), include instructions succinctly.
|
|
126
126
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
getModelInfo,
|
|
4
4
|
isProviderId,
|
|
5
5
|
} from '../../providers/src/utils.ts';
|
|
6
|
+
import type { ProviderPromptFamily } from '../../types/src/index.ts';
|
|
6
7
|
import type { UnderlyingProviderKey } from '../../providers/src/utils.ts';
|
|
7
8
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
8
9
|
import PROVIDER_OPENAI from './providers/openai.txt' with { type: 'text' };
|
|
@@ -40,6 +41,14 @@ function promptForFamily(family: UnderlyingProviderKey): string {
|
|
|
40
41
|
return (FAMILY_PROMPTS[family] ?? PROVIDER_DEFAULT).trim();
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
function promptForCustomFamily(
|
|
45
|
+
family: ProviderPromptFamily | undefined,
|
|
46
|
+
): string {
|
|
47
|
+
if (!family || family === 'default') return PROVIDER_DEFAULT.trim();
|
|
48
|
+
if (family === 'openai-compatible') return PROVIDER_DEFAULT.trim();
|
|
49
|
+
return (FAMILY_PROMPTS[family] ?? PROVIDER_DEFAULT).trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
async function readIfExists(path: string): Promise<string | undefined> {
|
|
44
53
|
try {
|
|
45
54
|
const f = Bun.file(path);
|
|
@@ -76,6 +85,7 @@ export async function providerBasePrompt(
|
|
|
76
85
|
provider: string,
|
|
77
86
|
modelId: string | undefined,
|
|
78
87
|
projectRoot: string,
|
|
88
|
+
customFamily?: ProviderPromptFamily,
|
|
79
89
|
): Promise<ProviderPromptResult> {
|
|
80
90
|
const id = String(provider || '').toLowerCase();
|
|
81
91
|
const { modelPaths, providerPaths } = getPromptOverridePaths({
|
|
@@ -100,6 +110,11 @@ export async function providerBasePrompt(
|
|
|
100
110
|
return { prompt: providerText, resolvedType: `custom:${id}` };
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
if (!isProviderId(id) && customFamily) {
|
|
114
|
+
const result = promptForCustomFamily(customFamily);
|
|
115
|
+
return { prompt: result, resolvedType: customFamily };
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
if (isProviderId(id) && modelId) {
|
|
104
119
|
const info = getModelInfo(id, modelId);
|
|
105
120
|
if (info?.ownedBy) {
|
|
@@ -4,14 +4,39 @@ import {
|
|
|
4
4
|
} from '../../config/src/index.ts';
|
|
5
5
|
import type { OttoConfig } from '../../config/src/index.ts';
|
|
6
6
|
import type { ProviderId } from '../../types/src/index.ts';
|
|
7
|
+
import {
|
|
8
|
+
getConfiguredProviderApiKey,
|
|
9
|
+
getConfiguredProviderEnvVar,
|
|
10
|
+
getProviderDefinition,
|
|
11
|
+
isBuiltInProviderId,
|
|
12
|
+
} from './registry.ts';
|
|
7
13
|
|
|
8
14
|
export async function isProviderAuthorized(
|
|
9
15
|
cfg: OttoConfig,
|
|
10
16
|
provider: ProviderId,
|
|
11
17
|
) {
|
|
18
|
+
const definition = getProviderDefinition(cfg, provider);
|
|
19
|
+
if (!definition) return false;
|
|
20
|
+
if (
|
|
21
|
+
definition.source === 'custom' &&
|
|
22
|
+
cfg.providers[String(provider)]?.enabled === false
|
|
23
|
+
)
|
|
24
|
+
return false;
|
|
25
|
+
if (getConfiguredProviderApiKey(cfg, provider)) return true;
|
|
26
|
+
if (definition.apiKeyEnv && process.env[definition.apiKeyEnv]) return true;
|
|
27
|
+
if (!isBuiltInProviderId(provider)) {
|
|
28
|
+
return !definition.apiKeyEnv && !cfg.providers[String(provider)]?.apiKey;
|
|
29
|
+
}
|
|
12
30
|
return await mgrIsAuthorized(provider, cfg.projectRoot);
|
|
13
31
|
}
|
|
14
32
|
|
|
15
33
|
export async function ensureProviderEnv(cfg: OttoConfig, provider: ProviderId) {
|
|
16
|
-
|
|
34
|
+
const envVar = getConfiguredProviderEnvVar(cfg, provider);
|
|
35
|
+
const apiKey = getConfiguredProviderApiKey(cfg, provider);
|
|
36
|
+
if (envVar && apiKey && !process.env[envVar]) {
|
|
37
|
+
process.env[envVar] = apiKey;
|
|
38
|
+
}
|
|
39
|
+
if (isBuiltInProviderId(provider)) {
|
|
40
|
+
await mgrEnsureEnv(provider, cfg.projectRoot);
|
|
41
|
+
}
|
|
17
42
|
}
|
|
@@ -3,15 +3,16 @@ import {
|
|
|
3
3
|
type OttoRouterModelCatalogEntry,
|
|
4
4
|
} from '@ottorouter/ai-sdk';
|
|
5
5
|
import type {
|
|
6
|
+
BuiltInProviderId,
|
|
6
7
|
ModelInfo,
|
|
7
8
|
ModelOwner,
|
|
8
9
|
ProviderCatalogEntry,
|
|
9
|
-
ProviderId,
|
|
10
10
|
} from '../../types/src/index.ts';
|
|
11
11
|
|
|
12
|
-
type CatalogMap = Partial<Record<
|
|
12
|
+
type CatalogMap = Partial<Record<BuiltInProviderId, ProviderCatalogEntry>>;
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const OLLAMA_CLOUD_ID: BuiltInProviderId = 'ollama-cloud';
|
|
15
|
+
const OTTOROUTER_ID: BuiltInProviderId = 'ottorouter';
|
|
15
16
|
|
|
16
17
|
const OWNER_NPM: Record<ModelOwner, string> = {
|
|
17
18
|
openai: '@ai-sdk/openai',
|
|
@@ -88,13 +89,27 @@ function buildOttoRouterEntry(): ProviderCatalogEntry | null {
|
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
function buildOllamaCloudEntry(): ProviderCatalogEntry {
|
|
93
|
+
return {
|
|
94
|
+
id: OLLAMA_CLOUD_ID,
|
|
95
|
+
label: 'Ollama Cloud',
|
|
96
|
+
env: ['OLLAMA_API_KEY'],
|
|
97
|
+
npm: 'ai-sdk-ollama',
|
|
98
|
+
api: 'https://ollama.com',
|
|
99
|
+
doc: 'https://docs.ollama.com/cloud',
|
|
100
|
+
models: [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
export function mergeManualCatalog(
|
|
92
105
|
base: CatalogMap,
|
|
93
|
-
): Record<
|
|
106
|
+
): Record<BuiltInProviderId, ProviderCatalogEntry> {
|
|
107
|
+
const ollamaCloudEntry = buildOllamaCloudEntry();
|
|
94
108
|
const manualEntry = buildOttoRouterEntry();
|
|
95
|
-
const merged: Record<
|
|
96
|
-
...(base as Record<
|
|
109
|
+
const merged: Record<BuiltInProviderId, ProviderCatalogEntry> = {
|
|
110
|
+
...(base as Record<BuiltInProviderId, ProviderCatalogEntry>),
|
|
97
111
|
};
|
|
112
|
+
merged[OLLAMA_CLOUD_ID] = ollamaCloudEntry;
|
|
98
113
|
if (manualEntry) {
|
|
99
114
|
merged[OTTOROUTER_ID] = manualEntry;
|
|
100
115
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
BuiltInProviderId,
|
|
2
3
|
ProviderCatalogEntry,
|
|
3
|
-
ProviderId,
|
|
4
4
|
} from '../../types/src/index.ts';
|
|
5
5
|
import { catalog as generatedCatalog } from './catalog.ts';
|
|
6
6
|
import { mergeManualCatalog } from './catalog-manual.ts';
|
|
7
7
|
|
|
8
|
-
export const catalog: Record<
|
|
8
|
+
export const catalog: Record<BuiltInProviderId, ProviderCatalogEntry> =
|
|
9
9
|
mergeManualCatalog(generatedCatalog);
|