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
Expand Up @@ -13,9 +13,10 @@
* Closed catalog of the machine-readable error codes exposed by the A2A-T SDK.
*
* <p>Each constant carries the layered {@code domain.semantic} code string (for example {@code content.param_missing}),
* the {@link Category} that decides which exception family carries it, and the names of the fact parameters the message
* template for the code renders. Message templates live in {@code prompt_resources/errors/{language}/errors.json}; use
* {@link ErrorMessages} to render them.
* the {@link Category} that decides which exception family carries it, and the names of the fact parameters the code
* declares. A message template may render a subset of the declared facts: {@code template.not_found} keeps
* {@code language} in its facts for programmatic diagnosis while its message only reports the missing template. Message
* templates live in {@code prompt_resources/errors/{language}/errors.json}; use {@link ErrorMessages} to render them.
*
* <p>The catalog is closed: codes returned by an LLM step that are not in this catalog are mapped to the per-domain
* {@code *.rule_violation} fallback constants by the callers, never surfaced raw.
Expand All @@ -26,7 +27,7 @@ public enum ErrorCatalog {

// domain: template (template resources)

/** The referenced template does not exist for the configured language. */
/** The referenced template is missing for the configured language; the message names the template URI. */
TEMPLATE_NOT_FOUND("template.not_found", Category.BUSINESS, "template_uri", "language"),

/** Rendering a template with its slot values failed. */
Expand Down Expand Up @@ -222,7 +223,10 @@ public static Optional<ErrorCatalog> byCode(@NonNull String code) {
}

/**
* Returns the names of the fact parameters the message template of the code renders.
* Returns the names of the fact parameters the code declares.
*
* <p>A message template may render a subset of these facts; the remaining ones stay available for programmatic
* diagnosis.
*
* @return fact parameter names, possibly empty, never null
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"template.not_found": "Template '{template_uri}' does not support language '{language}'; check the template URI and language setting",
"template.not_found": "Template '{template_uri}' does not exist",
"template.render_failed": "Failed to render template '{template_uri}': {reason}",
"template.load_failed": "Failed to read template resource '{resource_path}'",
"slot.schema_not_found": "Template '{template_uri}' is missing its slot schema (language '{language}')",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"template.not_found": "模板「{template_uri}」不支持语言「{language}」,请检查模板标识与语言配置",
"template.not_found": "模板「{template_uri}」不存在",
"template.render_failed": "模板「{template_uri}」渲染失败:{reason}",
"template.load_failed": "模板资源「{resource_path}」读取失败",
"slot.schema_not_found": "模板「{template_uri}」缺少参数定义文件(语言「{language}」)",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package net.openan.a2at.sdk.resources;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.util.Map;
import net.openan.a2at.sdk.core.exception.ErrorCatalog;
import net.openan.a2at.sdk.core.exception.ErrorMessages;
import org.junit.jupiter.api.Test;

/**
* Integration tests for the bundled {@code prompt_resources/errors/{language}/errors.json} resources rendered through
* {@link ErrorMessages}.
*
* <p>Tests cover the following scenarios:
*
* <ul>
* <li>The {@code template.not_found} message reports the missing template instead of claiming an unsupported language
* </ul>
*
* @since 2026-09
*/
class ErrorMessagesResourceTest {

private static final String UNKNOWN_URI = "Task-T/network-layer/does-not-exist/v1";

private static final Map<String, String> FACTS = Map.of("template_uri", UNKNOWN_URI, "language", "fr-FR");

/**
* Verifies the bundled Chinese {@code template.not_found} message reports the missing template and does not echo
* the configured language.
*
* <p>Scenario: Render the catalog entry with a template URI and an unsupported language. Expected result: the
* message states the template does not exist and omits the language.
*/
@Test
void should_reportMissingTemplate_When_renderedInChinese() {
String message = ErrorMessages.render(ErrorCatalog.TEMPLATE_NOT_FOUND, "zh-CN", FACTS);

assertEquals("模板「" + UNKNOWN_URI + "」不存在", message);
assertFalse(message.contains("fr-FR"), message);
}

/**
* Verifies the bundled English {@code template.not_found} message reports the missing template and does not echo
* the configured language.
*
* <p>Scenario: Render the catalog entry with a template URI and an unsupported language. Expected result: the
* message states the template does not exist and omits the language.
*/
@Test
void should_reportMissingTemplate_When_renderedInEnglish() {
String message = ErrorMessages.render(ErrorCatalog.TEMPLATE_NOT_FOUND, "en-US", FACTS);

assertEquals("Template '" + UNKNOWN_URI + "' does not exist", message);
assertFalse(message.contains("fr-FR"), message);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.openan.a2at.sdk.server.metadata;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -235,7 +236,11 @@ void extractPropagatesTemplateLoadErrorsAsGenerationFailures() {
assertEquals("template.not_found", error.getCode());
assertEquals("generation", error.getStage());
assertTrue(error.getMessage().contains("subscribe-incident"), "message must render the template URI");
assertTrue(error.getMessage().contains("zh-CN"), "message must render the language");
assertFalse(error.getMessage().contains("zh-CN"), "message must not echo the configured language");
assertEquals(
Map.of("template_uri", "subscribe-incident", "language", "zh-CN"),
error.getFacts(),
"facts must keep the language for programmatic diagnosis");
}

@Test
Expand Down
2 changes: 1 addition & 1 deletion docs/en/API_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1639,7 +1639,7 @@ result.failure() =

| Code | Category | Message (en-US) | Message (zh-CN) |
| ---- | -------- | ---------------- | --------------- |
| `template.not_found` | BUSINESS | Template '{template_uri}' does not support language '{language}'; check the template URI and language setting | 模板「{template_uri}」不支持语言「{language}」,请检查模板标识与语言配置 |
| `template.not_found` | BUSINESS | Template '{template_uri}' does not exist | 模板「{template_uri}」不存在 |
| `template.render_failed` | BUSINESS | Failed to render template '{template_uri}': {reason} | 模板「{template_uri}」渲染失败:{reason} |
| `template.load_failed` | INFRA | Failed to read template resource '{resource_path}' | 模板资源「{resource_path}」读取失败 |
| `slot.schema_not_found` | BUSINESS | Template '{template_uri}' is missing its slot schema (language '{language}') | 模板「{template_uri}」缺少参数定义文件(语言「{language}」) |
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/API参考.md
Original file line number Diff line number Diff line change
Expand Up @@ -1630,7 +1630,7 @@ result.failure() =

| 错误码 | 类别 | 消息(zh-CN) | 消息(en-US) |
| ----------------------------------------- | -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `template.not_found` | BUSINESS | 模板「{template_uri}」不支持语言「{language}」,请检查模板标识与语言配置 | Template '{template_uri}' does not support language '{language}'; check the template URI and language setting |
| `template.not_found` | BUSINESS | 模板「{template_uri}」不存在 | Template '{template_uri}' does not exist |
| `template.render_failed` | BUSINESS | 模板「{template_uri}」渲染失败:{reason} | Failed to render template '{template_uri}': {reason} |
| `template.load_failed` | INFRA | 模板资源「{resource_path}」读取失败 | Failed to read template resource '{resource_path}' |
| `slot.schema_not_found` | BUSINESS | 模板「{template_uri}」缺少参数定义文件(语言「{language}」) | Template '{template_uri}' is missing its slot schema (language '{language}') |
Expand Down
Loading