BxDolAIToolChatTitle.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. use NeuronAI\Tools\PropertyType;
  10. use NeuronAI\Tools\ToolProperty;
  11. /**
  12. * `chat_title` tool: the agent names the conversation it is in, once, as part of
  13. * its own reply — no second model request, no settings. Goes into
  14. * `sys_agents_chat_history`.`title` for the current thread (BxDolAiChat::setCurrentChatThreadTitle)
  15. * and shows up in the "Chats" history panel and the Studio chat popup.
  16. *
  17. * Without the tool (or when the agent never calls it) the lists fall back to the
  18. * first thing the person typed.
  19. */
  20. class BxDolAIToolChatTitle extends BxDolAITool
  21. {
  22. const MAX_WORDS = 6;
  23. const MAX_CHARS = 80;
  24. public function __construct()
  25. {
  26. parent::__construct(
  27. 'chat_title',
  28. 'Name THIS conversation: 3 to 6 words saying what it is about, in the language the user writes in. Call it once, in your first reply after the user\'s first real message (not after "[page opened…"). Do not mention the title to the user.',
  29. );
  30. }
  31. protected function properties(): array
  32. {
  33. return [
  34. new ToolProperty('title', PropertyType::STRING, 'Conversation title, 3-6 words, no quotes, no trailing period. Example: "Comment counter for post 291"', true),
  35. ];
  36. }
  37. public function __invoke($title): string
  38. {
  39. $sTitle = self::clean($title);
  40. if ($sTitle === '')
  41. return 'ignored: empty title';
  42. $iSet = BxDolAiChat::getInstance()->setCurrentChatThreadTitle($sTitle);
  43. if ($iSet === 0)
  44. return 'This conversation already has a title. Continue your reply.';
  45. return $iSet > 0
  46. ? 'Title saved. Continue your reply without mentioning it.'
  47. : 'ignored';
  48. }
  49. /**
  50. * One line, quotes and trailing punctuation gone, at most MAX_WORDS words and
  51. * MAX_CHARS characters.
  52. */
  53. public static function clean($mixed)
  54. {
  55. $s = strip_tags(is_string($mixed) ? $mixed : '');
  56. $s = preg_split('/\r\n|\r|\n/', trim($s))[0] ?? '';
  57. $s = trim($s, " \t\"'«»“”‘’`");
  58. $s = preg_replace('/\s+/u', ' ', $s);
  59. $s = rtrim($s, " .!。");
  60. if ($s === '')
  61. return '';
  62. $aWords = explode(' ', $s);
  63. if (count($aWords) > self::MAX_WORDS)
  64. $s = implode(' ', array_slice($aWords, 0, self::MAX_WORDS));
  65. if (get_mb_len($s) > self::MAX_CHARS)
  66. $s = rtrim(get_mb_substr($s, 0, self::MAX_CHARS - 1)) . '…';
  67. return $s;
  68. }
  69. }
  70. /** @} */