Account created on 23 June 2021, over 4 years ago
#

Merge Requests

More

Recent comments

🇮🇳India harivansh

Example config now:

uuid: 96d54c20-5996-4636-a13a-c0668c089ea9
langcode: en
status: true
dependencies: {  }
id: content_type_agent_triage
label: 'Content Type Agent'
description: 'This is the initial agents for content type/node types, that can figure out if you are trying to create, edit, delete or ask questions about content types.'
orchestration_agent: false
triage_agent: true
system_prompt: |-
  You are an Drupal 11 developer that specializes in content types/node types. You can create, edit, answer questions or delete content types using the tools to your disposal. 

  Thinks of the following instructions:
  1. When editing a content type, make sure that this content type exists. Otherwise tell them that it doesn't exist. 
  2. If you are on your second run, you will see actual information from the tools that has been run, they might answer a question or make it possible for you to start using the editing tools.
  3. If a question comes in that you think you can answer without any need to forward it, please do.  Otherwise use one of the tools to gather more information.
  4. If the instructions/questions have nothing to do with content types/nodes types, just answer that you are not the right agent to answer this.
  5. If you will do something, never respond that you will do something, instead just go ahead and do it.
  6. If you will be editing, make sure that the information exists about the node type first, so you can do a choice if you actually need to edit it. Do not explain why you do something, just return the tool.
  7. If you create or edit, you do not have to verify after that everything is ok.
secured_system_prompt: '[ai_agent:agent_instructions]'
max_loops: 3
default_information_tools: |
  node_types:
    label: 'Node Types'
    description: 'The existing node types on the system in YAML array with type (data name), label (name) and description'
    tool: 'ai_agent:list_config_entities'
    parameters:
      entity_type: node_type
      amount: 0
      fields:
        - type
        - name
        - description
structured_output_enabled: false
structured_output_schema: ''
tools:
  -
    tool_id: get_content_type_info
    provider: ai_agent
    active: true
    tool_settings:
      description_override: 'Description override test'
      require_usage: true
      use_artifact_storage: true
      return_directly: true
      progress_message: 'Custom progress message '
      property_overrides:
        -
          property_id: node_type
          overridden_description: 'Override node_type property description test'
          restriction_type: ''
          restriction_values: {  }
          restriction_hide_property: true
  -
    tool_id: edit_content_type
    provider: ai_agent
    active: true
    tool_settings:
      description_override: ''
      require_usage: false
      use_artifact_storage: false
      return_directly: true
      progress_message: ''
      property_overrides: {  }
  -
    tool_id: create_content_type
    provider: ai_agent
    active: true
    tool_settings:
      description_override: ''
      require_usage: false
      use_artifact_storage: false
      return_directly: false
      progress_message: ''
      property_overrides: {  }
🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

Hi kristen pol
I have removed the post update hook and redundant EntityPublishedInterface implementation as iterface is already implemented by EditorialContentEntityBase

🇮🇳India harivansh

Hi @mxr576
This is one demo,where I have use the ai runtime which dependes upon the symfony message to run the agen aync.

https://www.linkedin.com/posts/harivansh-sharma-826719102_drupal-ai-drup...

🇮🇳India harivansh

Hi @unqunq Thank you, I will try to refactor.

🇮🇳India harivansh

Will get to the issue, Right now this isn't priority.

🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

My changes are currently scattered, making it difficult to consolidate them. I’m currently working on building the foundational system for the workflow and need some time to architect it properly.
We can go ahead and close this issue.

🇮🇳India harivansh

Hi @marcus_johansson
The JSON schema example is good, but developers would benefit from seeing actual PHP code showing how to use it with ChatInput.
Somethng like this.

// Create your chat input
$chatInput = new ChatInput([
  new ChatMessage('user', 'Extract user info: harivansh sharma, @harivansh, harivansh@example.com'),
]);

// Define your schema
$schema = [
  'name' => 'user_data',
  'strict' => TRUE,
  'schema' => [
    'type' => 'object',
    'properties' => [
      'name' => ['type' => 'string'],
      'username' => ['type' => 'string'],
      'email' => ['type' => 'string', 'format' => 'email'],
    ],
    'required' => ['name', 'username', 'email'],
  ],
];

// Apply the schema
$chatInput->setChatStructuredJsonSchema($schema);

// Run inference
$response = $provider->chat($chatInput, 'model-id')->getNormalized();

// Parse the structured response
$userData = json_decode($response->getText(), TRUE);
// Result: [name => harivansh sharma, username => harivansh, email => harivansh@example.com]
🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

I think we should consolidate all tool configuration into a single tools property on the entity. This would eliminate the separate enabled_tools, locked_tools, and tool_operations arrays.

[
  'name' => 'tool_name',                    // Required: tool name
  'description' => 'Tool description',      // Required: tool description
  'input_schema' => [...],                  // Required: MCP tool schema

  // Configuration
  'enabled' => true,                        // Boolean: is tool enabled
  'locked' => false,                        // Boolean: is tool locked
  'operation' => 'read',                    // String: read|write
  
  // Locked definition (only if locked === true)
  'locked_definition' => [
    'name' => 'tool_name',
    'description' => 'Tool description',
    'input_schema' => [...],
  ],
]

To make this more maintainable and type-safe, we should also create dedicated DTOs/Value Objects for this:

ToolCollection - represents the collection of all tools
Tool - represents a single tool with all its configuration
InputSchema - represents the tool's input schema
LockDefinition - represents the locked tool definition
This approach would give us a single source of truth, cleaner code, and better type safety throughout the codebase.

What your though on this.

🇮🇳India harivansh

Assining to my self for review and work.

🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

@robertoperuzzo thank you for the feedback, I will work on your suggestion.

🇮🇳India harivansh

@jurgenhaas
Your solution works, but I think we should use named arguments instead

return new Collection(
  fields: $fields + $this->extraConstraints,
  allowExtraFields: false,
);

This is cleaner than passing NULL for unused parameters and aligns better with the #[HasNamedArguments] attribute on the Collection constructor. What do you think?

🇮🇳India harivansh

@marcus_johansson
I think we should add another column in the tool maintenance section
Something like this

🇮🇳India harivansh

sure

🇮🇳India harivansh

@marcus_johansson
We can add the "looked_tools" property (new field in the MCP config form) to store the locked tool definitions.
On subsequent tool fetches, locked tools use the saved definition instead of the server's response. This prevents malicious updates from changing tool behavior or injecting prompts
Users can unlock tools to receive updates when they trust the source

🇮🇳India harivansh

harivansh → made their first commit to this issue’s fork.

🇮🇳India harivansh

harivansh → made their first commit to this issue’s fork.

🇮🇳India harivansh

So I discussed with @marcus_johansson and @a.dmitriiev. We discussed a few approaches
I have come up with a new approach to solve the issue with the template pattern.
Issue: Enforce the provider class to dispatch the pre- and post events.

New approach: Hybrid Template Method with safety net pattern.

  • Move event dispatch into the provider base and operation traits (Template Method).
  • Keep a reflection-based safety net in the base class to wrap legacy providers and plugin operation types that haven’t migrated yet.
  • ProviderProxy no longer needs to own event dispatch; keep it temporarily (with @method docblocks) for IDE compatibility during migration and phase it out later.

New provider flow:
Provider uses trait and implements protected do*() methods.
Call path:

  • ChatTrait::chat() (public wrapper) -> calls:
  • dispatchOperation('chat', [$this, 'doChat'], $input, $model_id, $tags)

dispatchOperation():

  • Dispatch: PreGenerateResponseEvent
  • Call: OpenAiProvider::doChat() (protected implementation)
  • Dispatch: PostGenerateResponseEvent
  • Return OutputInterface to the caller

Old Provider :
Caller invokes a method on an unmigrated provider (e.g., $provider->chat()).
AiProviderClientBase::__call() intercepts the call and:

  • Uses reflection to check the method’s return type.
  • If the return type implements OutputInterface, it wraps the original call:
  • dispatchOperation('chat', function(...) { return $provider->chat(...); }, ...)
  • dispatchOperation() dispatches PreGenerateResponseEvent, calls the original OldProvider::chat() (public), dispatches PostGenerateResponseEvent, and returns the output.
  • If the method is not an operation, __call() invokes it directly (no wrapping).

Implementation:

  • AiProviderClientBase::dispatchOperation() — centralizes event dispatch and request ID handling.
  • AiProviderClientBase::__call() — safety net that detects operation methods via reflection and wraps them.
  • Operation base traits (Chat, Embeddings, TextToImage, TextToSpeech, SpeechToText, ImageToImage, Moderation):
  • Provide typed public wrapper methods (e.g., chat()) that call dispatchOperation().
  • Declare abstract protected function do*() methods providers must implement.
🇮🇳India harivansh

Apologies I made a bit of mess with MR, Took pull from 2.x branch by mistake.
I have these changes
- Removed `getCurrentThreadsKey()`, `setCurrentThreadsKey()`, and `removeCurrentThreadsKey()` methods
- Simplified `generateUniqueKey()` to always generate a new hash instead of checking server-side storage
- Updated `resetThread()` to return a new hash directly without server-side tracking
- Simplified `setThreadsKey()` by removing `session_one_thread` special handling

Thread ids were being stored in server-side sessions via PrivateTempStore, which caused session writes on every request. This negatively impacted page cache performance.
Threads are now fully managed client-side via localStorage already implemented in deepchat-init.js, and the server generates new ids via AJAX when needed DeepChatApi.php::setSession(). This eliminates unnecessary session writes and reduces page cache impact.

🇮🇳India harivansh

harivansh → made their first commit to this issue’s fork.

🇮🇳India harivansh

Hi @wouters_f
The AI Search module has been moved out of the AI core.
#3552884 ✨ Move out AI Search Active
https://www.drupal.org/project/issues/ai_search →

🇮🇳India harivansh

marcus_johansson
I have created the initial version of orchestration using Mermaid. I haven't added much styling yet, just experimenting. What do you think.

🇮🇳India harivansh

Performing the POC.

🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

harivansh → created an issue.

🇮🇳India harivansh

harivansh → created an issue.

Production build 0.71.5 2024