Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
74e0bc1
modify nunjucks parsing to stop parsing to string as [Object object]
cpinn Jan 8, 2026
d6a79e6
intercept actual rendering
cpinn Jan 8, 2026
ccafa05
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Jan 13, 2026
9490cb4
update from review comments, clean a few things up
cpinn Jan 13, 2026
9dabb9e
update tests and have specific mustache vs nunjucks sections
cpinn Jan 14, 2026
5df5f53
move image parsing to sdk
cpinn Jan 14, 2026
e8cc964
cleanup
cpinn Jan 14, 2026
d76c612
modify changes here to only alias dump to tojson, don't automatically…
cpinn Jan 22, 2026
3d507c8
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Jan 22, 2026
33dad3b
detect variables that are arrays of images or files
cpinn Jan 30, 2026
994382a
Merge main into branch: resolve generated_types conflicts
cpinn Jan 30, 2026
2c9a086
update inline attachment reference
cpinn Jan 30, 2026
131cb13
bump version
cpinn Jan 30, 2026
bd92dff
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Jan 30, 2026
6205db6
remove the string content
cpinn Jan 31, 2026
8eb949e
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Feb 2, 2026
e864daa
add external image as well
cpinn Feb 3, 2026
2e0b0fc
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Feb 6, 2026
635d262
export other type
cpinn Feb 6, 2026
a7eaa60
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Feb 19, 2026
cf24e7d
remove nunjucks
cpinn Feb 19, 2026
a1943d9
Merge branch 'main' into caitlin/modify-nunjucks-parsing-to-match-cus…
cpinn Feb 19, 2026
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
299 changes: 298 additions & 1 deletion js/src/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
Attachment,
deepCopyEvent,
renderMessage,
renderMessageImpl,
} from "./logger";
import {
parseTemplateFormat,
Expand Down Expand Up @@ -62,7 +63,15 @@ test("renderMessage with file content parts", () => {
],
};

const rendered = renderMessage(
const variables = {
item: "document",
image_url: "https://example.com/image.png",
file_data: "base64data",
file_id: "file-456",
filename: "report.pdf",
};

const rendered = renderMessageImpl(
(template) =>
template
.replace("{{item}}", "document")
Expand All @@ -71,6 +80,7 @@ test("renderMessage with file content parts", () => {
.replace("{{file_id}}", "file-456")
.replace("{{filename}}", "report.pdf"),
message,
variables,
);

expect(rendered.content).toEqual([
Expand All @@ -95,6 +105,293 @@ test("renderMessage with file content parts", () => {
]);
});

test("renderMessage expands attachment array in image_url parts", () => {
const message = {
role: "user" as const,
content: [
{
type: "image_url" as const,
image_url: { url: "{{images}}" },
},
],
};

const variables = {
images: ["https://example.com/img1.jpg", "https://example.com/img2.jpg"],
};

const rendered = renderMessageImpl(
(template) => template, // Template rendering shouldn't happen for attachment arrays
message,
variables,
);

expect(rendered.content).toEqual([
{
type: "image_url",
image_url: {
url: "https://example.com/img1.jpg",
},
},
{
type: "image_url",
image_url: {
url: "https://example.com/img2.jpg",
},
},
]);
});

test("renderMessage expands inline attachment array in image_url parts", () => {
const message = {
role: "user" as const,
content: [
{
type: "image_url" as const,
image_url: { url: "{{images}}" },
},
],
};

const variables = {
images: [
{
type: "inline_attachment",
src: "data:image/png;base64,abc",
content_type: "image/png",
},
{
type: "inline_attachment",
src: "data:image/jpeg;base64,def",
content_type: "image/jpeg",
},
],
};

const rendered = renderMessageImpl(
(template) => template,
message,
variables,
);

expect(rendered.content).toEqual([
{
type: "image_url",
image_url: {
url: {
type: "inline_attachment",
src: "data:image/png;base64,abc",
content_type: "image/png",
},
},
},
{
type: "image_url",
image_url: {
url: {
type: "inline_attachment",
src: "data:image/jpeg;base64,def",
content_type: "image/jpeg",
},
},
},
]);
});

test("renderMessage does NOT expand mixed content (text + variable)", () => {
const message = {
role: "user" as const,
content: "Look at {{images}}",
};

const variables = {
images: ["https://example.com/img1.jpg", "https://example.com/img2.jpg"],
};

const rendered = renderMessageImpl(
(template) => template.replace("{{images}}", "[array]"),
message,
variables,
);

// Mixed content is not expanded - just rendered normally
expect(rendered.content).toBe("Look at [array]");
});

test("renderMessage expands nested attachment arrays in image_url parts", () => {
const message = {
role: "user" as const,
content: [
{
type: "image_url" as const,
image_url: { url: "{{data.images}}" },
},
],
};

const variables = {
data: {
images: ["https://example.com/img1.jpg", "https://example.com/img2.jpg"],
},
};

const rendered = renderMessageImpl(
(template) => template, // Template rendering shouldn't happen
message,
variables,
);

expect(rendered.content).toEqual([
{
type: "image_url",
image_url: {
url: "https://example.com/img1.jpg",
},
},
{
type: "image_url",
image_url: {
url: "https://example.com/img2.jpg",
},
},
]);
});

test("renderMessage expands deeply nested attachment arrays in image_url parts", () => {
const message = {
role: "user" as const,
content: [
{
type: "image_url" as const,
image_url: { url: "{{user.profile.images}}" },
},
],
};

const variables = {
user: {
profile: {
images: [
{
type: "inline_attachment",
src: "data:image/png;base64,abc",
content_type: "image/png",
},
{
type: "inline_attachment",
src: "data:image/jpeg;base64,def",
content_type: "image/jpeg",
},
],
},
},
};

const rendered = renderMessageImpl(
(template) => template,
message,
variables,
);

expect(rendered.content).toEqual([
{
type: "image_url",
image_url: {
url: {
type: "inline_attachment",
src: "data:image/png;base64,abc",
content_type: "image/png",
},
},
},
{
type: "image_url",
image_url: {
url: {
type: "inline_attachment",
src: "data:image/jpeg;base64,def",
content_type: "image/jpeg",
},
},
},
]);
});

test("renderMessage handles single image_url (no array)", () => {
const message = {
role: "user" as const,
content: [
{
type: "image_url" as const,
image_url: {
url: "{{image}}",
},
},
],
};

const variables = {
image: "https://example.com/single.jpg",
};

const rendered = renderMessageImpl(
(template) =>
template.replace("{{image}}", "https://example.com/single.jpg"),
message,
variables,
);

expect(rendered.content).toEqual([
{
type: "image_url",
image_url: {
url: "https://example.com/single.jpg",
},
},
]);
});

test("renderMessage expands attachment arrays in structured content", () => {
// This tests the case where content is already an array with structured parts,
// and one part has a template variable for an attachment array
const message = {
role: "user" as const,
content: [
{ type: "text" as const, text: "Describe these images" },
{ type: "image_url" as const, image_url: { url: "{{attachments}}" } },
],
};

const variables = {
attachments: [
"https://example.com/img1.jpg",
"https://example.com/img2.jpg",
],
};

const rendered = renderMessageImpl(
(template) => template,
message,
variables,
);

// Should expand {{attachments}} into multiple image_url parts
expect(rendered.content).toEqual([
{
type: "text",
text: "Describe these images",
},
{
type: "image_url",
image_url: { url: "https://example.com/img1.jpg" },
},
{
type: "image_url",
image_url: { url: "https://example.com/img2.jpg" },
},
]);
});

test("verify MemoryBackgroundLogger intercepts logs", async () => {
// Log to memory for the tests.
_exportsForTestingOnly.simulateLoginForTests();
Expand Down
Loading