Implements deterministic model resolution (column → env map → pool → default) and adds AI identity fields to characters. Migration backfills existing rows with deterministic defaults. Controller uses resolved model and identity block in system prompts for contextual conversations.
142 lines
4.9 KiB
PHP
Executable File
142 lines
4.9 KiB
PHP
Executable File
<?php
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Character model map parser
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Turns AI_CHARACTER_MODELS entries such as "Maria=qwen/qwen3.7-flash:free"
|
|
| or "3=deepseek/deepseek-v4-flash-0731" into a lookup array keyed by
|
|
| lowercased character id or name. Invalid pairs are ignored.
|
|
|
|
|
*/
|
|
$parseCharacterModels = static function (string $raw): array {
|
|
$map = [];
|
|
|
|
foreach (explode(',', $raw) as $pair) {
|
|
$pair = trim($pair);
|
|
if ($pair === '' || ! str_contains($pair, '=')) {
|
|
continue;
|
|
}
|
|
|
|
[$key, $model] = array_map('trim', explode('=', $pair, 2));
|
|
if ($key !== '' && $model !== '') {
|
|
$map[strtolower($key)] = $model;
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
};
|
|
|
|
return [
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| OpenRouter.ai Integration
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Credentials and behaviour settings used by the AI agents to take
|
|
| strategic decisions through the OpenRouter.ai chat completions API.
|
|
| The API key must be provided via the OPENROUTER_API_KEY env variable
|
|
| and must never be committed to version control.
|
|
|
|
|
*/
|
|
|
|
'openrouter' => [
|
|
'api_key' => env('OPENROUTER_API_KEY'),
|
|
'base_url' => env('OPENROUTER_BASE_URL', 'https://openrouter.ai/api/v1'),
|
|
'timeout' => (int) env('OPENROUTER_TIMEOUT', 30),
|
|
'app_name' => env('APP_NAME', 'City10'),
|
|
'app_url' => env('APP_URL', 'http://localhost:16980'),
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Allow-listed Free Models
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Only the free models listed below may be selected for AI agents.
|
|
| Administrators cannot register agents with models outside this list,
|
|
| which keeps operating costs at zero and enforces the platform policy.
|
|
|
|
|
*/
|
|
|
|
'allowed_models' => [
|
|
'poolside/laguna-m.1:free',
|
|
'cohere/north-mini-code:free',
|
|
'deepseek/deepseek-v4-flash-0731:free',
|
|
'qwen/qwen3.8-27b:free',
|
|
'nvidia/nemotron-3-ultra-550b-a55b:free',
|
|
'nvidia/nemotron-3-super-120b-a12b:free',
|
|
'google/gemma-4-31b-it:free',
|
|
'google/gemma-4-26b-a4b-it:free',
|
|
'openai/gpt-oss-20b:free',
|
|
'nvidia/nemotron-nano-12b-v2-vl:free',
|
|
'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free',
|
|
'nvidia/nemotron-3-nano-30b-a3b:free',
|
|
'nvidia/nemotron-nano-9b-v2:free',
|
|
'poolside/laguna-xs-2.1:free',
|
|
'inclusionai/ling-3.0-flash-vl:free',
|
|
'qwen/qwen3.7-flash:free',
|
|
// Verified working free chat models (live probe of the OpenRouter
|
|
// catalogue). Safe defaults for per-character assignment.
|
|
'deepseek/deepseek-v4-flash-0731',
|
|
'nvidia/nemotron-3.5-lightning:free',
|
|
'liquid/lfm-2.5-2.6b:free',
|
|
'openrouter/free',
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Per-Character Model Pool (AI_MODELS)
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Comma-separated allow-listed models distributed deterministically
|
|
| across characters (each character keeps a stable own model). Falls
|
|
| back to AI_DEFAULT_MODEL when empty.
|
|
|
|
|
*/
|
|
|
|
'models' => array_values(array_filter(array_map(
|
|
'trim',
|
|
explode(',', (string) env('AI_MODELS', ''))
|
|
))),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Per-Character Model Map (AI_CHARACTER_MODELS)
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Explicit "id or name = model" overrides from the environment, e.g.
|
|
| "Maria=liquid/lfm-2.5-2.6b:free,7=openrouter/free". Takes priority
|
|
| over the pool; entries outside the allow-list are ignored.
|
|
|
|
|
*/
|
|
|
|
'character_models' => $parseCharacterModels((string) env('AI_CHARACTER_MODELS', '')),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Default Model
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Model assigned to newly created agents when none is specified.
|
|
|
|
|
*/
|
|
|
|
'default_model' => env('AI_DEFAULT_MODEL', 'deepseek/deepseek-v4-flash-0731'),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Agent Decision Cadence (seconds)
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Minimum interval between two reasoning calls for the same agent,
|
|
| protecting the upstream API from excessive usage.
|
|
|
|
|
*/
|
|
|
|
'think_interval' => (int) env('AI_THINK_INTERVAL', 60),
|
|
|
|
];
|