fix(tests): update resource alias syntax from 'res:' to 'res://' in tests and registry

Refactor tests and registry to use the new 'res://' syntax for resource aliases, ensuring consistency across the codebase. This change addresses alias handling in various test cases, including stream processing and registry encoding, to prevent data loss and improve resource reference management.
This commit is contained in:
wizardchen
2026-07-15 16:55:39 +08:00
committed by lyingbug
parent 38c594aec3
commit 0f4500b98f
4 changed files with 22 additions and 19 deletions
+2 -2
View File
@@ -53,7 +53,7 @@ func (m *mockChat) ChatStream(
func TestStreamLLMResourceAliasesRoundTrip(t *testing.T) {
const ref = "resource://AbCdEfGhIjKlMnOpQrStUv"
model := &mockChat{responses: []mockResponse{{chunks: []types.StreamResponse{
{ResponseType: types.ResponseTypeAnswer, Content: "![image](res:0"},
{ResponseType: types.ResponseTypeAnswer, Content: "![image](res://0"},
{ResponseType: types.ResponseTypeAnswer, Content: "001)", Done: true},
}}}}
engine := newTestEngine(t, model)
@@ -66,7 +66,7 @@ func TestStreamLLMResourceAliasesRoundTrip(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "![image]("+ref+")", result.Content)
require.Len(t, model.calls, 1)
require.Equal(t, "source=res:0001", model.calls[0][0].Content)
require.Equal(t, "source=res://0001", model.calls[0][0].Content)
}
func (m *mockChat) Chat(_ context.Context, _ []chat.Message, _ *chat.ChatOptions) (*types.ChatResponse, error) {
@@ -80,19 +80,19 @@ func (s *stubModelService) GetChatModel(context.Context, string) (chat.Chat, err
// TestStreamFlushesHeldAliasOnCancel verifies that when the request is cancelled
// mid-stream, the decoder's held-back alias suffix is flushed (emitted) rather
// than silently dropped. Without the ctx.Done() flush, "res:0" would be lost.
// than silently dropped. Without the ctx.Done() flush, "res://0" would be lost.
func TestStreamFlushesHeldAliasOnCancel(t *testing.T) {
const ref = "resource://AbCdEfGhIjKlMnOpQrStUv"
bus := &syncEventBus{}
model := &openStreamChat{chunks: []types.StreamResponse{
// Ends with a partial alias prefix ("res:0"), so the stream decoder
// Ends with a partial alias prefix ("res://0"), so the stream decoder
// holds it back waiting for the rest that never arrives before cancel.
{ResponseType: types.ResponseTypeAnswer, Content: "hello res:0"},
{ResponseType: types.ResponseTypeAnswer, Content: "hello res://0"},
}}
chatManage := &types.ChatManage{}
chatManage.SessionID = "sess-cancel"
chatManage.UserContent = ref // seeds the registry so res:0001 becomes a known alias
chatManage.UserContent = ref // seeds the registry so res://0001 becomes a known alias
chatManage.EventBus = bus
ctx, cancel := context.WithCancel(context.Background())
@@ -111,10 +111,10 @@ func TestStreamFlushesHeldAliasOnCancel(t *testing.T) {
cancel()
// After cancel, the held "res:0" suffix must be flushed as a final-answer chunk.
// After cancel, the held "res://0" suffix must be flushed as a final-answer chunk.
require.Eventually(t, func() bool {
for _, c := range bus.finalAnswerContents() {
if c == "res:0" {
if c == "res://0" {
return true
}
}
+5 -2
View File
@@ -26,7 +26,7 @@ var storedRefRE = regexp.MustCompile(
// aliasShapeRE matches the alias syntax produced by EncodeText. It is used only
// to spot alias-shaped tokens the model emitted that the registry cannot map
// back — either a hallucinated reference or a coincidental collision.
var aliasShapeRE = regexp.MustCompile(`res:\d{4,}`)
var aliasShapeRE = regexp.MustCompile(`res://\d{4,}`)
// Registry assigns low-entropy, request-local aliases to stable resource
// handles. It is safe to reuse across all rounds of one Agent execution.
@@ -55,7 +55,10 @@ func (r *Registry) EncodeText(value string) string {
if alias, ok := r.refToAlias[ref]; ok {
return alias
}
alias := fmt.Sprintf("res:%04d", len(r.aliasToRef)+1)
// A URL-shaped alias (scheme://digits) keeps the token low-entropy while
// looking enough like a link that the model reuses it verbatim inside
// Markdown image/link syntax instead of reasoning about or rewriting it.
alias := fmt.Sprintf("res://%04d", len(r.aliasToRef)+1)
r.refToAlias[ref] = alias
r.aliasToRef[alias] = ref
return alias
+9 -9
View File
@@ -11,7 +11,7 @@ func TestRegistryRoundTripAndDeduplicate(t *testing.T) {
r := NewRegistry()
ref := "resource://AbCdEfGhIjKlMnOpQrStUv"
encoded := r.EncodeText("![a](" + ref + ") and " + ref)
require.Equal(t, "![a](res:0001) and res:0001", encoded)
require.Equal(t, "![a](res://0001) and res://0001", encoded)
require.Equal(t, "![a]("+ref+") and "+ref, r.DecodeText(encoded))
}
@@ -19,7 +19,7 @@ func TestRegistryAliasesLegacyPhysicalReferencesDuringRollout(t *testing.T) {
r := NewRegistry()
ref := "storage://c0d93536-702c-4977-aa5e-fe670073c3cb/local://10000/exports/image.png"
encoded := r.EncodeText("![image](" + ref + ")")
require.Equal(t, "![image](res:0001)", encoded)
require.Equal(t, "![image](res://0001)", encoded)
require.Equal(t, "![image]("+ref+")", r.DecodeText(encoded))
}
@@ -29,15 +29,15 @@ func TestRegistryEncodesMessageCopies(t *testing.T) {
original := []chat.Message{{Role: "tool", Content: ref}}
encoded := r.EncodeMessages(original)
require.Equal(t, ref, original[0].Content)
require.Equal(t, "res:0001", encoded[0].Content)
require.Equal(t, "res://0001", encoded[0].Content)
}
func TestStreamDecoderRestoresSplitAlias(t *testing.T) {
r := NewRegistry()
ref := "resource://AbCdEfGhIjKlMnOpQrStUv"
require.Equal(t, "res:0001", r.EncodeText(ref))
require.Equal(t, "res://0001", r.EncodeText(ref))
d := NewStreamDecoder(r)
require.Equal(t, "before ", d.Feed("before res:0"))
require.Equal(t, "before ", d.Feed("before res://0"))
require.Equal(t, ref+" afte", d.Feed("001 after"))
require.Equal(t, "r", d.Flush())
}
@@ -45,16 +45,16 @@ func TestStreamDecoderRestoresSplitAlias(t *testing.T) {
func TestOrphanAliasesReportsUnresolvableTokens(t *testing.T) {
r := NewRegistry()
ref := "resource://AbCdEfGhIjKlMnOpQrStUv"
require.Equal(t, "res:0001", r.EncodeText(ref))
require.Equal(t, "res://0001", r.EncodeText(ref))
// Known alias resolves and leaves no orphan once decoded.
require.Nil(t, r.OrphanAliases(r.DecodeText("see res:0001")))
require.Nil(t, r.OrphanAliases(r.DecodeText("see res://0001")))
// A reference the registry never assigned is reported (deduplicated).
require.Equal(t, []string{"res:0099"}, r.OrphanAliases("look at res:0099 and res:0099"))
require.Equal(t, []string{"res://0099"}, r.OrphanAliases("look at res://0099 and res://0099"))
}
func TestOrphanAliasesNilRegistry(t *testing.T) {
var r *Registry
require.Equal(t, []string{"res:0001"}, r.OrphanAliases("res:0001"))
require.Equal(t, []string{"res://0001"}, r.OrphanAliases("res://0001"))
}