cai-exos-systems/daveadmin-exos-demo:api/tool-creator.php
api/tool-creator.php
```text
<?php
declare(strict_types=1);
/**
* EXOS Tool Creator
*
* Turns an agent intent into a Factory-ready Estate Manifest, MCP tool spec,
* Copilot digest, and optional MCP Factory generation response.
*/
require_once dirname(__DIR__) . '/auth.php';
set_time_limit(120);
ini_set('memory_limit', '256M');
demoRequireApiLogin();
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['error' => 'Method not allowed']);
exit;
}
if (!demoOriginAllowed()) {
http_response_code(403);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['error' => 'Origin not allowed']);
exit;
}
$ipRate = demoRateLimit('tool_creator_ip', demoClientIp(), demoApiRequestLimit(), demoApiWindowSeconds());
$sessionRate = demoRateLimit('tool_creator_session', session_id(), demoApiRequestLimit(), demoApiWindowSeconds());
if (!$ipRate['allowed'] || !$sessionRate['allowed']) {
http_response_code(429);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['error' => 'Too many requests']);
exit;
}
$body = json_decode(file_get_contents('php://input') ?: '{}', true);
if (!is_array($body)) {
$body = [];
}
$message = trim((string)($body['message'] ?? ''));
$profile = is_array($body['tool_profile'] ?? null) ? $body['tool_profile'] : [];
$requestedModel = toolCleanText(demoEnv('EXOS_CREATOR_LLM_MODEL', 'bnl-telecom'), 'bnl-telecom');
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
if (ob_get_level()) {
ob_end_clean();
}
ob_implicit_flush(true);
function toolSse(array $data): void
{
echo 'data: ' . json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n\n";
if (ob_get_level()) {
ob_flush();
}
flush();
}
function toolCleanText(mixed $value, string $fallback = ''): string
{
$text = trim((string)$value);
return $text !== '' ? mb_substr($text, 0, 260) : $fallback;
}
function toolLongText(mixed $value, string $fallback = ''): string
{
$text = trim((string)$value);
return $text !== '' ? mb_substr($text, 0, 4000) : $fallback;
}
function toolSlug(string $value): string
{
$slug = strtolower(trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $value) ?? '', '-'));
return $slug !== '' ? mb_substr($slug, 0, 72) : 'exos-toolset';
}
function toolRegistryFile(): string
{
return (string)demoEnv(
'EXOS_TOOL_REGISTRY_FILE',
demoSupportDir() . DIRECTORY_SEPARATOR . 'tool-creator-registry.json'
);
}
function toolExportDir(): string
{
$dir = (string)demoEnv(
'EXOS_TOOL_EXPORT_DIR',
demoSupportDir() . DIRECTORY_SEPARATOR . 'tool-creator-exports'
);
if (!is_dir($dir)) {
@mkdir($dir, 0775, true);
}
return $dir;
}
api/tool-creator.php 'customer', 'adapter' => 'crm', 'tmf_api' => 'TMF629', 'label' => 'Get account manager', 'description' => 'Return the account manager and escalation owner for a customer.', 'side_effect' => 'read', 'policy_tags' => ['PII'], 'input_schema' => ['account_number' => 'string'], ], ]; } function toolSelectedDomains(array $profile, string $message): array { $valid = ['billing', 'product', 'order', 'customer', 'case']; $selected = []; foreach (($profile['target_domains'] ?? []) as $domain) { $domain = strtolower(trim((string)$domain)); if (in_array($domain, $valid, true)) { $selected[] = $domain; } } $text = strtolower($message . ' ' . implode(' ', array_filter([ $profile['name'] ?? '', $profile['domain'] ?? '', $profile['mission'] ?? '', ], 'is_scalar'))); $terms = [ 'billing' => ['bill', 'billing', 'invoice', 'charge'], 'product' => ['product', 'catalog', 'catalogue', 'offering', 'price'], 'order' => ['order', 'fulfill', 'fulfil', 'q2o', 'quote'], 'customer' => ['customer', 'account', 'profile', 'manager'], 'case' => ['case', 'ticket', 'trouble', 'support', 'incident'], ]; foreach ($terms as $domain => $needles) { foreach ($needles as $needle) { if (str_contains($text, $needle)) { $selected[] = $domain; break; } } } return array_values(array_unique($selected ?: ['billing', 'product', 'order', 'customer', 'case'])); } function toolPolicy(): array { return [ 'read_only' => ['allow_writes' => false, 'approval_required' => true, 'label' => 'Read-only'], 'demo_safe' => ['allow_writes' => true, 'approval_required' => true, 'label' => 'Demo-safe writes'], 'approval_gated' => ['allow_writes' => true, 'approval_required' => true, 'label' => 'Approval-gated writes'], ]; } function toolSelectNames(array $domains, string $writePolicy, array $catalog): array { $names = []; foreach ($catalog as $name => $tool) { if (!in_array($tool['domain'], $domains, true)) { continue; } $isWrite = $tool['side_effect'] === 'write'; if ($isWrite && $writePolicy === 'read_only') { continue; } if ($name === 'add-product-with-price' && $writePolicy !== 'approval_gated') { continue; } $names[] = $name; } return array_values(array_unique($names)); } function toolAdapterBase(string $target): array { $target = in_array($target, ['mock', 'fossbilling', 'customer-placeholder'], true) ? $target : 'fossbilling'; if ($target === 'mock') { return [ 'billing_system' => 'MockBSS Billing', 'product_system' => 'MockBSS Catalog', 'order_system' => 'MockBSS Orders', 'crm_system' => 'MockBSS Care', 'foss_url' => '${MOCK_BSS_URL}', 'crm_url' => '${MOCK_CRM_URL}', 'token' => '${MOCK_BSS_TOKEN}', 'crm_id' => '${MOCK_CRM_CLIENT_ID}', 'crm_secret' => '${MOCK_CRM_CLIENT_SECRET}', ]; } if ($target === 'customer-placeholder') { return [ 'billing_system' => 'Customer Billing BSS', 'product_system' => 'Customer Product Catalog', 'order_system' => 'Customer Order Management', 'crm_system' => 'Customer CRM / Care', 'foss_url' => '${CUSTOMER_BSS_URL}', 'crm_url' => '${CUSTOMER_CRM_URL}', 'token' => '${CUSTOMER_BSS_TOKEN}', 'crm_id' => '${CUSTOMER_CRM_CLIENT_ID}', 'crm_secret' => '${CUSTOMER_CRM_CLIENT_SECRET}', ]; } return [ 'billing_system' => 'FOSSbilling', 'product_system' => 'FOSSbilling', 'order_system' => 'FOSSbilling', 'crm_system' => 'SuiteCRM', 'foss_url' => '${FOSSBILLING_URL}', 'crm_url' => '${SUITECRM_URL}', 'token' => '${FOSSBILLING_TOKEN}', 'crm_id' => '${SUITECRM_CLIENT_ID}', 'crm_secret' => '${SUITECRM_CLIENT_SECRET}', ]; }
api/tool-creator.php 'query' => $query, 'latency_ms' => (int)((microtime(true) - $t0) * 1000), 'results' => $results]; } function toolLlmSketch(array $profile, array $toolSpec, string $model): array { $base = rtrim((string)demoEnv('EXOS_LITELLM_BASE', 'http://10.0.1.10:4000'), '/'); $apiKey = demoEnv('EXOS_CREATOR_LLM_KEY') ?? demoEnv('LITELLM_API_KEY') ?? demoEnv('OPENAI_API_KEY'); $prompt = 'Return compact JSON with keys summary, risks, copilot_topics for this EXOS MCP toolset: ' . json_encode(['profile' => $profile, 'tools' => array_column($toolSpec, 'name')], JSON_UNESCAPED_SLASHES); $headers = ['Content-Type: application/json']; if ($apiKey) { $headers[] = 'Authorization: Bearer ' . $apiKey; } $ch = curl_init($base . '/v1/chat/completions'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode([ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => 'You are a telecom BSS tool architect. Return JSON only.'], ['role' => 'user', 'content' => $prompt], ], 'temperature' => 0.1, 'max_tokens' => 700, ], JSON_UNESCAPED_SLASHES), ]); $raw = curl_exec($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); if ($err || $code >= 400 || !$raw) { return ['configured' => (bool)$apiKey, 'status' => $code, 'error' => $err ?: 'LiteLLM request unavailable', 'results' => null]; } $decoded = json_decode((string)$raw, true); $content = (string)($decoded['choices'][0]['message']['content'] ?? ''); $json = json_decode($content, true); return ['configured' => true, 'status' => $code, 'results' => is_array($json) ? $json : ['summary' => mb_substr($content, 0, 800)]]; } function toolBuildSpec(array $toolNames, array $catalog, string $writePolicy): array { return array_map(static function (string $name) use ($catalog, $writePolicy): array { $tool = $catalog[$name]; $approval = in_array('approval_required', $tool['policy_tags'], true) || ($tool['side_effect'] === 'write' && $writePolicy !== 'demo_safe'); return [ 'name' => $name, 'label' => $tool['label'], 'description' => $tool['description'], 'adapter' => $tool['adapter'], 'domain' => $tool['domain'], 'tmf_api' => $tool['tmf_api'], 'side_effect' => $tool['side_effect'], 'policy_tags' => $tool['policy_tags'], 'approval_required' => $approval, 'input_schema' => toolInputSchema($tool['input_schema']), ]; }, $toolNames); } function toolInputSchema(array $fields): array { $properties = []; $required = []; foreach ($fields as $name => $definition) { if (!is_string($name) || $name === '') { continue; } $text = strtolower((string)$definition); $type = str_contains($text, 'integer') || str_contains($text, 'number') ? 'number' : 'string'; $properties[$name] = [ 'type' => $type, 'description' => ucwords(str_replace('_', ' ', $name)), ]; if (!str_contains($text, 'optional')) { $required[] = $name; } } return [ 'type' => 'object', 'properties' => $properties, 'required' => $required, 'additionalProperties' => false, ]; } function toolBuildManifest(array $profile, array $toolNames, array $toolSpec, array $adapters, array $corpus, array $llm, string $model): array { $customerName = toolCleanText($profile['customer_name'] ?? $profile['name'] ?? '', 'EXOS Demo Operator'); $environment = in_array(($profile['environment'] ?? 'demo'), ['demo', 'staging', 'production'], true) ? (string)$profile['environment'] : 'demo'; $tmfApis = array_values(array_unique(array_column($toolSpec, 'tmf_api'))); $writePolicy = toolCleanText($profile['write_policy'] ?? '', 'approval_gated'); $policyTags = []; foreach ($toolSpec as $tool) { foreach (($tool['policy_tags'] ?? []) as $tag) { $policyTags[] = (string)$tag; } } $corpusRefs = array_map(static fn(array $r): array => [ 'title' => $r['title'] ?? '', 'source' => $r['source'] ?? '', 'score' => $r['score'] ?? null, ], array_slice($corpus['results'] ?? [], 0, 5));
api/tool-creator.php $adapters, $corpus, $llm, $requestedModel); toolSse([ 'event' => 'tool_start', 'tool' => 'mcp_factory_generate', 'tmf_api' => 'Factory', 'system' => 'Exosphere MCP Factory', 'input' => ['tools' => $toolNames, 'adapters' => array_keys($adapters)], ]); $factory = toolCallFactory($manifest); toolSse([ 'event' => 'tool_result', 'tool' => 'mcp_factory_generate', 'tmf_api' => 'Factory', 'output' => [ 'ok' => $factory['ok'], 'status' => $factory['status'], 'stats' => $factory['response']['stats'] ?? null, 'error' => $factory['error'] ?? null, ], ]); $copilot = toolBuildCopilotDigest($profile, $manifest, $toolSpec, $factory); $entry = toolPersist($profile, $manifest, $toolSpec, $copilot, $factory); toolSse([ 'event' => 'answer_json', 'data' => [ 'mode_label' => 'Tool Creator', 'tmf_apis_used' => $entry['tmf_apis_used'], 'status' => $factory['ok'] ? 'generated' : 'artifact-ready', 'key_findings' => [ 'Generated Factory-ready Estate Manifest with ' . count($toolSpec) . ' MCP tools.', 'Mapped adapters: ' . implode(', ', array_keys($adapters)) . '.', $factory['ok'] ? 'MCP Factory returned generated package metadata.' : 'Factory call did not complete; artifacts are still available for manual Factory import.', ], 'recommended_actions' => [ 'Review estate-manifest.json before connecting a real operator BSS.', 'Use copilot-digest.json as the enterprise action summary for Copilot Studio conversations.', 'Promote this to Cartographer discovery once customer OpenAPI/Postman/IAM details are available.', ], 'standards_references' => $entry['tmf_apis_used'], 'registry_id' => $entry['id'], 'exports' => $entry['exports'], 'factory_stats' => $entry['factory_stats'], ], ]); $answer = "## {$entry['toolset_name']}\n\n" . "**Registry:** {$entry['id']}\n" . "**Factory status:** {$entry['factory_status']}\n" . "**Tools:** {$entry['tool_count']} across {$entry['adapter_count']} adapters\n\n" . "**Exports**\n" . "- Estate Manifest: {$entry['exports']['estate_manifest']}\n" . "- Tool Spec: {$entry['exports']['tool_spec']}\n" . "- Copilot Digest: {$entry['exports']['copilot_digest']}\n" . "- Factory Response: {$entry['exports']['factory_response']}\n\n" . "**Enabled tools**\n" . implode("\n", array_map(static fn(array $tool): string => "- {$tool['name']} ({$tool['tmf_api']}, {$tool['side_effect']})", $toolSpec)) . "\n\n**Exosphere story**\n" . "Agent Creator defines the brain and guardrails. Tool Creator turns that intent into a governed MCP tool contract. MCP Factory turns the manifest into the deployable server package Copilot can consume at enterprise scale."; toolSse(['event' => 'message', 'answer' => $answer]); toolSse([ 'event' => 'message_end', 'conversation_id' => 'toolcreator-' . bin2hex(random_bytes(6)), 'model' => 'tool-creator-v1', ]); ```
api/tool-creator.php 'customer', 'adapter' => 'crm', 'tmf_api' => 'TMF629', 'label' => 'Get account manager', 'description' => 'Return the account manager and escalation owner for a customer.', 'side_effect' => 'read', 'policy_tags' => ['PII'], 'input_schema' => ['account_number' => 'string'], ], ]; } function toolSelectedDomains(array $profile, string $message): array { $valid = ['billing', 'product', 'order', 'customer', 'case']; $selected = []; foreach (($profile['target_domains'] ?? []) as $domain) { $domain = strtolower(trim((string)$domain)); if (in_array($domain, $valid, true)) { $selected[] = $domain; } } $text = strtolower($message . ' ' . implode(' ', array_filter([ $profile['name'] ?? '', $profile['domain'] ?? '', $profile['mission'] ?? '', ], 'is_scalar'))); $terms = [ 'billing' => ['bill', 'billing', 'invoice', 'charge'], 'product' => ['product', 'catalog', 'catalogue', 'offering', 'price'], 'order' => ['order', 'fulfill', 'fulfil', 'q2o', 'quote'], 'customer' => ['customer', 'account', 'profile', 'manager'], 'case' => ['case', 'ticket', 'trouble', 'support', 'incident'], ]; foreach ($terms as $domain => $needles) { foreach ($needles as $needle) { if (str_contains($text, $needle)) { $selected[] = $domain; break; } } } return array_values(array_unique($selected ?: ['billing', 'product', 'order', 'customer', 'case'])); } function toolPolicy(): array { return [ 'read_only' => ['allow_writes' => false, 'approval_required' => true, 'label' => 'Read-only'], 'demo_safe' => ['allow_writes' => true, 'approval_required' => true, 'label' => 'Demo-safe writes'], 'approval_gated' => ['allow_writes' => true, 'approval_required' => true, 'label' => 'Approval-gated writes'], ]; } function toolSelectNames(array $domains, string $writePolicy, array $catalog): array { $names = []; foreach ($catalog as $name => $tool) { if (!in_array($tool['domain'], $domains, true)) { continue; } $isWrite = $tool['side_effect'] === 'write'; if ($isWrite && $writePolicy === 'read_only') { continue; } if ($name === 'add-product-with-price' && $writePolicy !== 'approval_gated') { continue; } $names[] = $name; } return array_values(array_unique($names)); } function toolAdapterBase(string $target): array { $target = in_array($target, ['mock', 'fossbilling', 'customer-placeholder'], true) ? $target : 'fossbilling'; if ($target === 'mock') { return [ 'billing_system' => 'MockBSS Billing', 'product_system' => 'MockBSS Catalog', 'order_system' => 'MockBSS Orders', 'crm_system' => 'MockBSS Care', 'foss_url' => '${MOCK_BSS_URL}', 'crm_url' => '${MOCK_CRM_URL}', 'token' => '${MOCK_BSS_TOKEN}', 'crm_id' => '${MOCK_CRM_CLIENT_ID}', 'crm_secret' => '${MOCK_CRM_CLIENT_SECRET}', ]; } if ($target === 'customer-placeholder') { return [ 'billing_system' => 'Customer Billing BSS', 'product_system' => 'Customer Product Catalog', 'order_system' => 'Customer Order Management', 'crm_system' => 'Customer CRM / Care', 'foss_url' => '${CUSTOMER_BSS_URL}', 'crm_url' => '${CUSTOMER_CRM_URL}', 'token' => '${CUSTOMER_BSS_TOKEN}', 'crm_id' => '${CUSTOMER_CRM_CLIENT_ID}', 'crm_secret' => '${CUSTOMER_CRM_CLIENT_SECRET}', ]; } return [ 'billing_system' => 'FOSSbilling', 'product_system' => 'FOSSbilling', 'order_system' => 'FOSSbilling', 'crm_system' => 'SuiteCRM', 'foss_url' => '${FOSSBILLING_URL}', 'crm_url' => '${SUITECRM_URL}', 'token' => '${FOSSBILLING_TOKEN}', 'crm_id' => '${SUITECRM_CLIENT_ID}', 'crm_secret' => '${SUITECRM_CLIENT_SECRET}', ]; }
api/tool-creator.php 'query' => $query, 'latency_ms' => (int)((microtime(true) - $t0) * 1000), 'results' => $results]; } function toolLlmSketch(array $profile, array $toolSpec, string $model): array { $base = rtrim((string)demoEnv('EXOS_LITELLM_BASE', 'http://10.0.1.10:4000'), '/'); $apiKey = demoEnv('EXOS_CREATOR_LLM_KEY') ?? demoEnv('LITELLM_API_KEY') ?? demoEnv('OPENAI_API_KEY'); $prompt = 'Return compact JSON with keys summary, risks, copilot_topics for this EXOS MCP toolset: ' . json_encode(['profile' => $profile, 'tools' => array_column($toolSpec, 'name')], JSON_UNESCAPED_SLASHES); $headers = ['Content-Type: application/json']; if ($apiKey) { $headers[] = 'Authorization: Bearer ' . $apiKey; } $ch = curl_init($base . '/v1/chat/completions'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20, CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode([ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => 'You are a telecom BSS tool architect. Return JSON only.'], ['role' => 'user', 'content' => $prompt], ], 'temperature' => 0.1, 'max_tokens' => 700, ], JSON_UNESCAPED_SLASHES), ]); $raw = curl_exec($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); if ($err || $code >= 400 || !$raw) { return ['configured' => (bool)$apiKey, 'status' => $code, 'error' => $err ?: 'LiteLLM request unavailable', 'results' => null]; } $decoded = json_decode((string)$raw, true); $content = (string)($decoded['choices'][0]['message']['content'] ?? ''); $json = json_decode($content, true); return ['configured' => true, 'status' => $code, 'results' => is_array($json) ? $json : ['summary' => mb_substr($content, 0, 800)]]; } function toolBuildSpec(array $toolNames, array $catalog, string $writePolicy): array { return array_map(static function (string $name) use ($catalog, $writePolicy): array { $tool = $catalog[$name]; $approval = in_array('approval_required', $tool['policy_tags'], true) || ($tool['side_effect'] === 'write' && $writePolicy !== 'demo_safe'); return [ 'name' => $name, 'label' => $tool['label'], 'description' => $tool['description'], 'adapter' => $tool['adapter'], 'domain' => $tool['domain'], 'tmf_api' => $tool['tmf_api'], 'side_effect' => $tool['side_effect'], 'policy_tags' => $tool['policy_tags'], 'approval_required' => $approval, 'input_schema' => toolInputSchema($tool['input_schema']), ]; }, $toolNames); } function toolInputSchema(array $fields): array { $properties = []; $required = []; foreach ($fields as $name => $definition) { if (!is_string($name) || $name === '') { continue; } $text = strtolower((string)$definition); $type = str_contains($text, 'integer') || str_contains($text, 'number') ? 'number' : 'string'; $properties[$name] = [ 'type' => $type, 'description' => ucwords(str_replace('_', ' ', $name)), ]; if (!str_contains($text, 'optional')) { $required[] = $name; } } return [ 'type' => 'object', 'properties' => $properties, 'required' => $required, 'additionalProperties' => false, ]; } function toolBuildManifest(array $profile, array $toolNames, array $toolSpec, array $adapters, array $corpus, array $llm, string $model): array { $customerName = toolCleanText($profile['customer_name'] ?? $profile['name'] ?? '', 'EXOS Demo Operator'); $environment = in_array(($profile['environment'] ?? 'demo'), ['demo', 'staging', 'production'], true) ? (string)$profile['environment'] : 'demo'; $tmfApis = array_values(array_unique(array_column($toolSpec, 'tmf_api'))); $writePolicy = toolCleanText($profile['write_policy'] ?? '', 'approval_gated'); $policyTags = []; foreach ($toolSpec as $tool) { foreach (($tool['policy_tags'] ?? []) as $tag) { $policyTags[] = (string)$tag; } } $corpusRefs = array_map(static fn(array $r): array => [ 'title' => $r['title'] ?? '', 'source' => $r['source'] ?? '', 'score' => $r['score'] ?? null, ], array_slice($corpus['results'] ?? [], 0, 5));
api/tool-creator.php $adapters, $corpus, $llm, $requestedModel); toolSse([ 'event' => 'tool_start', 'tool' => 'mcp_factory_generate', 'tmf_api' => 'Factory', 'system' => 'Exosphere MCP Factory', 'input' => ['tools' => $toolNames, 'adapters' => array_keys($adapters)], ]); $factory = toolCallFactory($manifest); toolSse([ 'event' => 'tool_result', 'tool' => 'mcp_factory_generate', 'tmf_api' => 'Factory', 'output' => [ 'ok' => $factory['ok'], 'status' => $factory['status'], 'stats' => $factory['response']['stats'] ?? null, 'error' => $factory['error'] ?? null, ], ]); $copilot = toolBuildCopilotDigest($profile, $manifest, $toolSpec, $factory); $entry = toolPersist($profile, $manifest, $toolSpec, $copilot, $factory); toolSse([ 'event' => 'answer_json', 'data' => [ 'mode_label' => 'Tool Creator', 'tmf_apis_used' => $entry['tmf_apis_used'], 'status' => $factory['ok'] ? 'generated' : 'artifact-ready', 'key_findings' => [ 'Generated Factory-ready Estate Manifest with ' . count($toolSpec) . ' MCP tools.', 'Mapped adapters: ' . implode(', ', array_keys($adapters)) . '.', $factory['ok'] ? 'MCP Factory returned generated package metadata.' : 'Factory call did not complete; artifacts are still available for manual Factory import.', ], 'recommended_actions' => [ 'Review estate-manifest.json before connecting a real operator BSS.', 'Use copilot-digest.json as the enterprise action summary for Copilot Studio conversations.', 'Promote this to Cartographer discovery once customer OpenAPI/Postman/IAM details are available.', ], 'standards_references' => $entry['tmf_apis_used'], 'registry_id' => $entry['id'], 'exports' => $entry['exports'], 'factory_stats' => $entry['factory_stats'], ], ]); $answer = "## {$entry['toolset_name']}\n\n" . "**Registry:** {$entry['id']}\n" . "**Factory status:** {$entry['factory_status']}\n" . "**Tools:** {$entry['tool_count']} across {$entry['adapter_count']} adapters\n\n" . "**Exports**\n" . "- Estate Manifest: {$entry['exports']['estate_manifest']}\n" . "- Tool Spec: {$entry['exports']['tool_spec']}\n" . "- Copilot Digest: {$entry['exports']['copilot_digest']}\n" . "- Factory Response: {$entry['exports']['factory_response']}\n\n" . "**Enabled tools**\n" . implode("\n", array_map(static fn(array $tool): string => "- {$tool['name']} ({$tool['tmf_api']}, {$tool['side_effect']})", $toolSpec)) . "\n\n**Exosphere story**\n" . "Agent Creator defines the brain and guardrails. Tool Creator turns that intent into a governed MCP tool contract. MCP Factory turns the manifest into the deployable server package Copilot can consume at enterprise scale."; toolSse(['event' => 'message', 'answer' => $answer]); toolSse([ 'event' => 'message_end', 'conversation_id' => 'toolcreator-' . bin2hex(random_bytes(6)), 'model' => 'tool-creator-v1', ]); ```