Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions apps/sim/app/w/[id]/components/workflow-block/workflow-block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { parseCronToHumanReadable } from '@/lib/schedules/utils'
import { cn, formatDateTime, validateName } from '@/lib/utils'
import type { BlockConfig, SubBlockConfig } from '@/blocks/types'
import { useExecutionStore } from '@/stores/execution/store'
import { useOllamaStore } from '@/stores/ollama/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { mergeSubblockState } from '@/stores/workflows/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
Expand Down Expand Up @@ -279,6 +280,7 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
}

const isAdvancedMode = useWorkflowStore.getState().blocks[blockId]?.advancedMode ?? false
const ollamaModels = useOllamaStore.getState().models

// Filter visible blocks and those that meet their conditions
const visibleSubBlocks = subBlocks.filter((block) => {
Expand All @@ -299,15 +301,25 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
? stateToUse[block.condition.and.field]?.value
: undefined

// Special handling for Ollama models condition
let conditionValue = block.condition.value
if (
block.condition.field === 'model' &&
Array.isArray(conditionValue) &&
conditionValue.length === 0
) {
conditionValue = ollamaModels
}

// Check if the condition value is an array
const isValueMatch = Array.isArray(block.condition.value)
const isValueMatch = Array.isArray(conditionValue)
? fieldValue != null &&
(block.condition.not
? !block.condition.value.includes(fieldValue as string | number | boolean)
: block.condition.value.includes(fieldValue as string | number | boolean))
? !conditionValue.includes(fieldValue as string | number | boolean)
: conditionValue.includes(fieldValue as string | number | boolean))
: block.condition.not
? fieldValue !== block.condition.value
: fieldValue === block.condition.value
? fieldValue !== conditionValue
: fieldValue === conditionValue

// Check both conditions if 'and' is present
const isAndValueMatch =
Expand Down
31 changes: 6 additions & 25 deletions apps/sim/blocks/blocks/agent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AgentIcon } from '@/components/icons'
import { isHosted } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { MODELS_TEMP_RANGE_0_1, MODELS_TEMP_RANGE_0_2 } from '@/providers/model-capabilities'
import { getAllModelProviders, getBaseModelProviders } from '@/providers/utils'
Expand Down Expand Up @@ -121,30 +120,12 @@ export const AgentBlock: BlockConfig<AgentResponse> = {
placeholder: 'Enter your API key',
password: true,
connectionDroppable: false,
// Hide API key for all OpenAI and Claude models when running on hosted version
condition: isHosted
? {
field: 'model',
// Include all OpenAI models and Claude models for which we don't show the API key field
value: [
// OpenAI models
'gpt-4o',
'o1',
'o1-mini',
'o1-preview',
'o3',
'o3-preview',
'o4-mini',
'gpt-4.1',
// Claude models
'claude-sonnet-4-20250514',
'claude-opus-4-20250514',
'claude-3-7-sonnet-20250219',
'claude-3-5-sonnet-20240620',
],
not: true, // Show for all models EXCEPT those listed
}
: undefined, // Show for all models in non-hosted environments
condition: {
// Hide API key for all OpenAI and Claude models when running on hosted version
field: 'model', // Include all Ollama models for which we don't show the API key field
value: useOllamaStore.getState().models,
not: true, // Show for all models EXCEPT those listed
}, // Show for all models in non-hosted environments
},
{
id: 'tools',
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/lib/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const env = createEnv({
NEXT_PUBLIC_GOOGLE_CLIENT_ID: z.string().optional(),
NEXT_PUBLIC_GOOGLE_API_KEY: z.string().optional(),
NEXT_PUBLIC_GOOGLE_PROJECT_NUMBER: z.string().optional(),
NEXT_PUBLIC_OLLAMA_URL: z.string().url().optional(),
},

// Only need to define client variables, server variables are automatically handled
Expand All @@ -123,5 +124,6 @@ export const env = createEnv({
NEXT_PUBLIC_GOOGLE_CLIENT_ID: getEnv('NEXT_PUBLIC_GOOGLE_CLIENT_ID'),
NEXT_PUBLIC_GOOGLE_API_KEY: getEnv('NEXT_PUBLIC_GOOGLE_API_KEY'),
NEXT_PUBLIC_GOOGLE_PROJECT_NUMBER: getEnv('NEXT_PUBLIC_GOOGLE_PROJECT_NUMBER'),
NEXT_PUBLIC_OLLAMA_URL: getEnv('NEXT_PUBLIC_OLLAMA_URL'),
},
})
14 changes: 6 additions & 8 deletions apps/sim/providers/ollama/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { ProviderConfig, ProviderRequest, ProviderResponse, TimeSegment } f
import type { ModelsObject } from './types'

const logger = createLogger('OllamaProvider')
const OLLAMA_HOST = env.OLLAMA_URL || 'http://localhost:11434'
const OLLAMA_HOST = env.NEXT_PUBLIC_OLLAMA_URL || 'http://localhost:11434'

export const ollamaProvider: ProviderConfig = {
id: 'ollama',
Expand All @@ -19,21 +19,20 @@ export const ollamaProvider: ProviderConfig = {

// Initialize the provider by fetching available models
async initialize() {
if (typeof window !== 'undefined') {
logger.info('Skipping Ollama initialization on client side to avoid CORS issues')
return
}

const OLLAMA_HOST = env.NEXT_PUBLIC_OLLAMA_URL || 'http://localhost:11434'
try {
logger.info('Ollama host', { OLLAMA_HOST })
const response = await fetch(`${OLLAMA_HOST}/api/tags`)
if (!response.ok) {
console.log('response', response)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Avoid using console.log for debugging in production code. Use the logger instead for consistency.

Suggested change
console.log('response', response)
logger.debug('response', response)

useOllamaStore.getState().setModels([])
logger.warn('Ollama service is not available. The provider will be disabled.')
return
}
const data = (await response.json()) as ModelsObject
this.models = data.models.map((model) => model.name)
useOllamaStore.getState().setModels(this.models)
logger.info('Ollama models initialized', { models: this.models })
} catch (error) {
logger.warn('Ollama model instantiation failed. The provider will be disabled.', {
error: error instanceof Error ? error.message : 'Unknown error',
Expand All @@ -42,7 +41,6 @@ export const ollamaProvider: ProviderConfig = {
},

executeRequest: async (request: ProviderRequest): Promise<ProviderResponse> => {
console.log(request)
logger.info('Preparing Ollama request', {
model: request.model,
hasSystemPrompt: !!request.systemPrompt,
Expand All @@ -58,8 +56,8 @@ export const ollamaProvider: ProviderConfig = {
try {
// Prepare messages array
const ollama = new OpenAI({
apiKey: 'empty',
baseURL: `${OLLAMA_HOST}/v1`,
apiKey: 'ollama',
})

// Start with an empty array for all messages
Expand Down
7 changes: 5 additions & 2 deletions apps/sim/providers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,9 @@ export function getApiKey(provider: string, model: string, userProvidedKey?: str
// Use server key rotation for all OpenAI models and Anthropic's Claude models on the hosted platform
const isOpenAIModel = provider === 'openai'
const isClaudeModel = provider === 'anthropic'
const isOllamaModel = provider === 'ollama'

if (isHosted && (isOpenAIModel || isClaudeModel)) {
if (isHosted && (isOpenAIModel || (isClaudeModel && !isOllamaModel))) {
try {
// Import the key rotation function
const { getRotatingApiKey } = require('@/lib/utils')
Expand All @@ -496,14 +497,16 @@ export function getApiKey(provider: string, model: string, userProvidedKey?: str
if (hasUserKey) {
return userProvidedKey!
}

// Otherwise, throw an error
throw new Error(`No API key available for ${provider} ${model}`)
}
}

// For all other cases, require user-provided key
if (!hasUserKey) {
if (isOllamaModel) {
return 'ollama'
}
throw new Error(`API key is required for ${provider} ${model}`)
}

Expand Down
2 changes: 1 addition & 1 deletion docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ services:
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID:-placeholder}
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
- NEXT_PUBLIC_OLLAMA_URL=${NEXT_PUBLIC_OLLAMA_URL:-http://localhost:11434}
depends_on:
db:
condition: service_healthy
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ services:
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID:-placeholder}
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
- NEXT_PUBLIC_OLLAMA_URL=${NEXT_PUBLIC_OLLAMA_URL:-http://localhost:11434}
depends_on:
db:
condition: service_healthy
Expand Down