Skip to content

Commit e69884e

Browse files
hoonjicopybara-github
authored andcommitted
ADK changes
PiperOrigin-RevId: 843176851
1 parent 41bf1ea commit e69884e

File tree

3 files changed

+114
-33
lines changed

3 files changed

+114
-33
lines changed

src/app/components/chat/chat.component.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,4 +1204,38 @@ describe('ChatComponent', () => {
12041204
});
12051205
});
12061206
});
1207+
1208+
describe('Artifacts', () => {
1209+
it(
1210+
'should only fetch artifact version once for the same artifactId and versionId',
1211+
async () => {
1212+
mockArtifactService.getArtifactVersion.and.returnValue(
1213+
of({
1214+
inlineData: {
1215+
mimeType: 'image/png',
1216+
data: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
1217+
},
1218+
}),
1219+
);
1220+
const sseEvent = {
1221+
id: 'event-1',
1222+
author: 'bot',
1223+
content: {role: 'bot', parts: []},
1224+
actions: {
1225+
artifactDelta: {'artifact-1': 'version-1'},
1226+
},
1227+
};
1228+
component.userInput = 'test message';
1229+
1230+
await component.sendMessage(
1231+
new KeyboardEvent('keydown', {key: 'Enter'}),
1232+
);
1233+
mockAgentService.runSseResponse.next(sseEvent);
1234+
mockAgentService.runSseResponse.next(sseEvent);
1235+
fixture.detectChanges();
1236+
1237+
expect(mockArtifactService.getArtifactVersion).toHaveBeenCalledTimes(1);
1238+
},
1239+
);
1240+
});
12071241
});

src/app/components/chat/chat.component.ts

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,29 @@ export class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
805805
return `data:${mimeType};base64,${fixedBase64Data}`;
806806
}
807807

808+
private handleArtifactFetchFailure(
809+
placeholderIndex: number, artifactId: string, versionId: string) {
810+
this.openSnackBar(
811+
'Failed to fetch artifact data',
812+
'OK',
813+
);
814+
// Remove placeholder message and artifact on failure
815+
this.messages.update(
816+
messages => messages.filter((m, i) => i !== placeholderIndex));
817+
this.artifacts = this.artifacts.filter(
818+
a => a.id !== artifactId || a.versionId !== versionId);
819+
}
820+
808821
private renderArtifact(artifactId: string, versionId: string) {
822+
// If artifact/version already exists, do nothing.
823+
const artifactExists = this.artifacts.some(
824+
(artifact) =>
825+
artifact.id === artifactId && artifact.versionId === versionId,
826+
);
827+
if (artifactExists) {
828+
return;
829+
}
830+
809831
// Add a placeholder message for the artifact
810832
// Feed the placeholder with the artifact data after it's fetched
811833
let message = {
@@ -819,8 +841,19 @@ export class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
819841

820842
const currentMessages = this.messages();
821843
const lastMessage = currentMessages[currentMessages.length - 1];
822-
const currentIndex = lastMessage?.isLoading ? currentMessages.length - 2 :
823-
currentMessages.length - 1;
844+
const placeholderIndex = lastMessage?.isLoading ?
845+
currentMessages.length - 2 :
846+
currentMessages.length - 1;
847+
848+
// Add placeholder artifact.
849+
const placeholderArtifact = {
850+
id: artifactId,
851+
versionId,
852+
data: '',
853+
mimeType: 'image/png',
854+
mediaType: MediaType.IMAGE,
855+
};
856+
this.artifacts = [...this.artifacts, placeholderArtifact];
824857

825858
this.artifactService
826859
.getArtifactVersion(
@@ -830,40 +863,53 @@ export class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
830863
artifactId,
831864
versionId,
832865
)
833-
.subscribe((res) => {
834-
const mimeType = res.inlineData.mimeType;
835-
const base64Data =
836-
this.formatBase64Data(res.inlineData.data, mimeType);
866+
.subscribe({
867+
next: (res) => {
868+
const {mimeType, data} = res.inlineData ?? {};
869+
if (!mimeType || !data) {
870+
this.handleArtifactFetchFailure(
871+
placeholderIndex, artifactId, versionId);
872+
return;
873+
}
874+
const base64Data =
875+
this.formatBase64Data(data, mimeType);
837876

838-
const mediaType = getMediaTypeFromMimetype(mimeType);
877+
const mediaType = getMediaTypeFromMimetype(mimeType);
839878

840-
let inlineData = {
841-
name: this.createDefaultArtifactName(mimeType),
842-
data: base64Data,
843-
mimeType: mimeType,
844-
mediaType,
845-
};
846-
847-
this.messages.update(messages => {
848-
const newMessages = [...messages];
849-
newMessages[currentIndex] = {
850-
role: 'bot',
851-
inlineData,
879+
const inlineData = {
880+
name: this.createDefaultArtifactName(mimeType),
881+
data: base64Data,
882+
mimeType: mimeType,
883+
mediaType,
852884
};
853-
return newMessages;
854-
});
855885

856-
// To trigger ngOnChanges in the artifact tab component
857-
this.artifacts = [
858-
...this.artifacts,
859-
{
860-
id: artifactId,
861-
data: base64Data,
862-
mimeType,
863-
versionId,
864-
mediaType: getMediaTypeFromMimetype(mimeType),
865-
},
866-
];
886+
this.messages.update(messages => {
887+
const newMessages = [...messages];
888+
newMessages[placeholderIndex] = {
889+
role: 'bot',
890+
inlineData,
891+
};
892+
return newMessages;
893+
});
894+
895+
// Update placeholder artifact with fetched data.
896+
this.artifacts = this.artifacts.map(artifact => {
897+
if (artifact.id === artifactId && artifact.versionId === versionId) {
898+
return {
899+
id: artifactId,
900+
versionId,
901+
data: base64Data,
902+
mimeType,
903+
mediaType,
904+
};
905+
}
906+
return artifact;
907+
});
908+
},
909+
error: (err) => {
910+
this.handleArtifactFetchFailure(
911+
placeholderIndex, artifactId, versionId);
912+
}
867913
});
868914
}
869915

src/app/core/services/interfaces/artifact.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17+
import {Part} from '../../models/types';
1718

1819
import {InjectionToken} from '@angular/core';
1920
import {Observable} from 'rxjs';
@@ -36,5 +37,5 @@ export declare abstract class ArtifactService {
3637
sessionId: string,
3738
artifactName: string,
3839
versionId: string,
39-
): Observable<any>;
40+
): Observable<Part>;
4041
}

0 commit comments

Comments
 (0)