Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[FEATURE] Port SaveFilesAsArtifactsPlugin from adk-python

未关闭
#1,411 1 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@hemasekhar-p 已经在做这个了。

开始于 2026年8月10日。

  • #1412 来自 @svetanis —— 未关闭

评估

这个 Issue 还没有评估数据。

描述

needs review

Please make sure you read the contribution guide and file the issues in the right place.
Contribution guide.

🔴 Required Information

Is your feature request related to a specific problem?

adk-python deprecated save_input_blobs_as_artifacts in favour of SaveFilesAsArtifactsPlugin.
adk-java has the parameter but not the plugin, so RunConfig.saveInputBlobsAsArtifacts(true) is the
only way to keep uploaded bytes out of every later LLM request — and it loses two things the plugin
provides.

1. The uploaded file name is discarded. Runner names every artifact
artifact_{invocationId}_{index} and never reads Blob.displayName.

// Runner, in the blob-offload loop
String fileName = "artifact_" + invocationContext.invocationId() + "_" + i;

An upload of report.pdf is stored as artifact_<invocationId>_1, so anything that later loads it
must work from an opaque id that appears nowhere but the placeholder text.

2. Nothing is reported to the session. The user event carries a state delta only, so
EventActions.artifactDelta stays empty and the session's artifact bookkeeping never records the
upload.

// Runner.appendNewMessageToSession — no artifactDelta is set on this event
if (stateDelta != null && !stateDelta.isEmpty()) {
  eventBuilder.actions(EventActions.builder().stateDelta(new ConcurrentHashMap<>(stateDelta)).build());
}

Both behaviours live in the plugin.

Describe the Solution You'd Like

SaveFilesAsArtifactsPlugin in com.google.adk.plugins, registered on a Runner like any other
plugin. For each inlineData part of the incoming user message it would:

  • save the part to the configured BaseArtifactService, named from Blob.displayName, falling back
    to artifact_{invocationId}_{index} when the blob carries no name;
  • replace it with [Uploaded Artifact: "<name>"] in the message that reaches the model and is
    appended to the session, matching adk-python's wording;
  • report the saved versions through EventActions.artifactDelta;
  • on a failed save, keep the original part and log, without failing the invocation — as in
    adk-python, the log is the only signal, so an unreachable artifact service degrades silently to no
    offload.

attach_file_reference would not be ported: it needs
get_artifact_version(...).canonical_uri, which has no equivalent on BaseArtifactService, so it
would require an SPI change across every implementation. Separate change.

Impact on your work

Applications wanting adk-python's behaviour must reimplement it in application code, where it will
drift from upstream. Not blocking, and no timeline — this is a parity gap, not an outage.

Willingness to contribute

Yes. A PR follows immediately after this issue: one new plugin class plus a small package-private helper, with tests. No existing file is modified, and the only new public surface is the plugin class itself.


🟡 Recommended Information

Describe Alternatives You've Considered

Teach the existing flag to read Blob.displayName and set artifactDelta. Smaller diff, but it
adds behaviour to the parameter adk-python is steering users away from, and adk-java would still have
no plugin — widening the divergence rather than closing it.

Implement the plugin in application code. This works using public API only, and is how the
behaviour below was verified. It is per-application boilerplate for something a plugin surface exists
to ship once.

Proposed API / Implementation

Registration needs no new API — the existing surfaces already accept it:

Runner runner = Runner.builder()
    .agent(agent)
    .appName("my-app")
    .artifactService(new InMemoryArtifactService())
    .sessionService(new InMemorySessionService())
    .plugins(new SaveFilesAsArtifactsPlugin())   // also App.Builder.plugins(...) and
    .build();                                    // InMemoryRunner(agent, appName, plugins)

Two hooks, both already wired into the runtime:

public class SaveFilesAsArtifactsPlugin extends BasePlugin {

  @Override
  public Maybe<Content> onUserMessageCallback(InvocationContext ctx, Content userMessage) {
    // save each inlineData part, swap it for [Uploaded Artifact: "<name>"],
    // stash {fileName: version} under a temp: state key, return the rebuilt Content
  }

  @Override
  public Maybe<Content> beforeAgentCallback(BaseAgent agent, CallbackContext callbackContext) {
    // drain the stash into callbackContext.eventActions().artifactDelta(), return Maybe.empty()
  }
}

The state hand-off exists because onUserMessageCallback runs before any EventActions exists, so
the saved versions cannot be reported from there. adk-python solves it the same way.

Additional Context

Same upload, same runner, differing only in which mechanism performs the offload:

--- Run A: RunConfig.saveInputBlobsAsArtifacts(true) ---
  user attached                     : blob with displayName="report.pdf"
  artifacts stored in the session   : artifact_e-eb41628a-9812-43a0-88d0-7b121706190b_1
  EventActions.artifactDelta        : (none)
  message appended to the session   :
                                      - text: "read the attachment"
                                      - text: "Uploaded file: artifact_e-eb41628a-…_1. It has been saved to the artifacts"

--- Run B: SaveFilesAsArtifactsPlugin (the proposed port) ---
  user attached                     : blob with displayName="report.pdf"
  artifacts stored in the session   : report.pdf
  EventActions.artifactDelta        : {report.pdf=0}
  message appended to the session   :
                                      - text: "read the attachment"
                                      - text: "[Uploaded Artifact: "report.pdf"]"

Both offload the payload losslessly and both show the model a placeholder instead of the bytes — the
gap is the file name and the bookkeeping, not the offload.

Observed on 1.7.2-SNAPSHOT, Windows 11 (not OS-specific), with a stub model and with
gemini-3.5-flash; both mechanisms run before the model call.

主要语言
Java
星标
1.7k
派生
433
平均合并
3 天 13 小时
30 天内合并 PR
42

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

google/adk-java 的其他 Issue

查看 google/adk-java 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。