@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.
Files changed (34) hide show
  1. package/package.json +3 -2
  2. package/src/config/src/index.ts +5 -0
  3. package/src/config/src/manager.ts +106 -30
  4. package/src/core/src/providers/resolver.ts +28 -1
  5. package/src/core/src/tools/builtin/bash.ts +2 -2
  6. package/src/core/src/tools/builtin/bash.txt +1 -1
  7. package/src/core/src/tools/builtin/fs/edit-shared.ts +1 -1
  8. package/src/core/src/tools/builtin/fs/edit.txt +2 -2
  9. package/src/core/src/tools/builtin/fs/write.txt +1 -1
  10. package/src/core/src/tools/loader.ts +133 -81
  11. package/src/index.ts +33 -0
  12. package/src/prompts/src/agents/build.txt +3 -4
  13. package/src/prompts/src/providers/default.txt +1 -1
  14. package/src/prompts/src/providers/glm.txt +1 -1
  15. package/src/prompts/src/providers/google.txt +2 -2
  16. package/src/prompts/src/providers/moonshot.txt +1 -1
  17. package/src/prompts/src/providers/openai.txt +3 -3
  18. package/src/prompts/src/providers.ts +15 -0
  19. package/src/providers/src/authorization.ts +26 -1
  20. package/src/providers/src/catalog-manual.ts +21 -6
  21. package/src/providers/src/catalog-merged.ts +2 -2
  22. package/src/providers/src/catalog.ts +10284 -10283
  23. package/src/providers/src/env.ts +10 -5
  24. package/src/providers/src/index.ts +26 -0
  25. package/src/providers/src/ollama-discovery.ts +149 -0
  26. package/src/providers/src/pricing.ts +3 -0
  27. package/src/providers/src/registry.ts +258 -0
  28. package/src/providers/src/utils.ts +10 -3
  29. package/src/providers/src/validate.ts +63 -2
  30. package/src/skills/index.ts +3 -0
  31. package/src/skills/tool.ts +28 -36
  32. package/src/types/src/config.ts +34 -8
  33. package/src/types/src/index.ts +4 -0
  34. 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 `edit` / `multiedit` for targeted changes; use `apply_patch` for structural or multi-file edits; use `write` only for new files or near-total rewrites.
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 `edit`, `multiedit`, `apply_patch`, `write`, `bash` — strictly adhering to Core Mandates.
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: edit, multiedit, write, or apply_patch to apply the refactoring to 'src/auth.py']
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 `edit` / `multiedit` for targeted changes; use `apply_patch` for structural or multi-file edits; use `write` only for new files or near-total rewrites.
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 targeted edits in existing files, prefer `edit` and `multiedit`. For structural diffs or file add/delete/rename, use `apply_patch`.
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 `apply_patch` — the call fails if it didn't work.
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 `apply_patch`, don't tell users to "save the file" — just reference the path.
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
- await mgrEnsureEnv(provider, cfg.projectRoot);
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<ProviderId, ProviderCatalogEntry>>;
12
+ type CatalogMap = Partial<Record<BuiltInProviderId, ProviderCatalogEntry>>;
13
13
 
14
- const OTTOROUTER_ID: ProviderId = 'ottorouter';
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<ProviderId, ProviderCatalogEntry> {
106
+ ): Record<BuiltInProviderId, ProviderCatalogEntry> {
107
+ const ollamaCloudEntry = buildOllamaCloudEntry();
94
108
  const manualEntry = buildOttoRouterEntry();
95
- const merged: Record<ProviderId, ProviderCatalogEntry> = {
96
- ...(base as Record<ProviderId, ProviderCatalogEntry>),
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<ProviderId, ProviderCatalogEntry> =
8
+ export const catalog: Record<BuiltInProviderId, ProviderCatalogEntry> =
9
9
  mergeManualCatalog(generatedCatalog);