Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2025 Deutsche Telekom AG and others
//
// SPDX-License-Identifier: Apache-2.0

package org.eclipse.lmos.arc.assistants.support.extensions

import org.eclipse.lmos.arc.agents.dsl.DSLContext

/**
* Builds the system prompt for [org.eclipse.lmos.arc.assistants.support.filters.UseCaseMatcher].
*
* Register an implementation as a Spring bean (or via [org.eclipse.lmos.arc.agents.dsl.BeanProvider])
* to override the default classification prompt at runtime.
*/
fun interface UseCasePromptProvider {
/**
* @param useCases Formatted use case definitions passed to the matcher LLM call.
* @param context Current DSL context (e.g. for loading external prompt files).
*/
suspend fun buildSystemPrompt(useCases: String, context: DSLContext): String
}
97 changes: 7 additions & 90 deletions arc-assistants/src/main/kotlin/filters/UseCaseMatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package org.eclipse.lmos.arc.assistants.support.filters

import org.eclipse.lmos.arc.agents.dsl.DSLContext
import org.eclipse.lmos.arc.agents.dsl.extensions.llm
import org.eclipse.lmos.arc.agents.dsl.getOptional
import org.eclipse.lmos.arc.assistants.support.extensions.UseCasePromptProvider
import org.eclipse.lmos.arc.core.getOrNull
import org.eclipse.lmos.arc.core.onFailure
import org.slf4j.LoggerFactory
Expand All @@ -14,101 +16,16 @@ class UseCaseMatcher(private val model: String? = null) {

private val log = LoggerFactory.getLogger(this.javaClass)

private fun system(useCases: String) = """
You are a classification system.

Your task is to match an assistant message to the most appropriate use case,
based on the provided use case definitions and their solutions.

## Rules
Each use case includes a Solution, describing the expected assistant behavior.
Match based on semantic meaning, not exact wording.
Prefer the use case whose solution best aligns with the intent of the assistant message.
If no use case clearly matches, return <UNKNOWN>.
Output must be only one label in angle brackets.

----

## Examples

### Example 1
UseCases
UseCase: password_reset
Solution
Ask the customer to restart their router to reset their router.

#### UseCase: password_forgotton
Solution
Ask the customer to send an email to customer support.

Assistant
Please restart your router.

Output:<password_reset>

### Example 2
UseCases
UseCase: billing_issue
Solution
Ask the customer to check their invoice or contact billing support.

UseCase: technical_issue
Solution
Guide the customer through troubleshooting steps.

Assistant
Please review your invoice or reach out to billing support.

Output: <billing_issue>

### Example 3
UseCases
UseCase: account_locked
Solution
Tell the customer to wait 15 minutes before trying again.

UseCase: password_reset
Solution
Ask the customer to reset their password using the reset link.

Assistant
You can reset your password using the link we sent you.

Output: <password_reset>

### Example 4 (No Match)
UseCases
UseCase: shipping_delay
Solution
Inform the customer about delayed delivery.

UseCase: refund_request
Solution
Guide the customer through requesting a refund.

Assistant
Our office hours are Monday to Friday, 9am–5pm.

Output: <UNKNOWN>

----

Now classify:

#UseCases
$useCases


Output: (only the label in angle brackets)
"""

suspend fun matchUseCase(
message: String,
useCases: String,
context: DSLContext
): String? {
val systemPrompt = context.getOptional<UseCasePromptProvider>()
?.buildSystemPrompt(useCases, context)
?: UseCaseMatcherPrompts.build(useCases)
val result = context.llm(
system = system(useCases),
system = systemPrompt,
user = "Assistant Message: $message",
model = model
).onFailure {
Expand All @@ -122,4 +39,4 @@ class UseCaseMatcher(private val model: String? = null) {
log.info("Matched UseCase found: $result")
return useCase
}
}
}
101 changes: 101 additions & 0 deletions arc-assistants/src/main/kotlin/filters/UseCaseMatcherPrompts.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: 2025 Deutsche Telekom AG and others
//
// SPDX-License-Identifier: Apache-2.0

package org.eclipse.lmos.arc.assistants.support.filters

/**
* Default system prompt template for [UseCaseMatcher].
* Replace `{useCases}` with the formatted use case definitions at runtime.
*/
object UseCaseMatcherPrompts {
const val TEMPLATE = """
You are a classification system.

Your task is to match an assistant message to the most appropriate use case,
based on the provided use case definitions and their solutions.

## Rules
Each use case includes a Solution, describing the expected assistant behavior.
Match based on semantic meaning, not exact wording.
Prefer the use case whose solution best aligns with the intent of the assistant message.
If no use case clearly matches, return <UNKNOWN>.
Output must be only one label in angle brackets.

----

## Examples

### Example 1
UseCases
UseCase: password_reset
Solution
Ask the customer to restart their router to reset their router.

#### UseCase: password_forgotton
Solution
Ask the customer to send an email to customer support.

Assistant
Please restart your router.

Output:<password_reset>

### Example 2
UseCases
UseCase: billing_issue
Solution
Ask the customer to check their invoice or contact billing support.

UseCase: technical_issue
Solution
Guide the customer through troubleshooting steps.

Assistant
Please review your invoice or reach out to billing support.

Output: <billing_issue>

### Example 3
UseCases
UseCase: account_locked
Solution
Tell the customer to wait 15 minutes before trying again.

UseCase: password_reset
Solution
Ask the customer to reset their password using the reset link.

Assistant
You can reset your password using the link we sent you.

Output: <password_reset>

### Example 4 (No Match)
UseCases
UseCase: shipping_delay
Solution
Inform the customer about delayed delivery.

UseCase: refund_request
Solution
Guide the customer through requesting a refund.

Assistant
Our office hours are Monday to Friday, 9am–5pm.

Output: <UNKNOWN>

----

Now classify:

#UseCases
{useCases}


Output: (only the label in angle brackets)
"""

fun build(useCases: String): String = TEMPLATE.replace("{useCases}", useCases)
}
Loading