feat: add cli support#57
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR expands the “experience disclosure” and management subsystems to support progressive (L1/L2/L3) disclosure of experience documents, introduces CLI-bound skill import/export workflows (including references/assets handling), and hardens Python string literal serialization for Graal-based execution.
Changes:
- Add progressive disclosure manifests (
referenceManifest/assetManifest) and a gatedread_exp_doctool for on-demand reference document reads. - Extend skill package import/export to preserve references/assets, create CLI TOOL experiences, and add management-console UI for previewing and lazily loading assets + re-summarizing references.
- Refactor Python string literal serialization to a JSON-based approach and add unit tests; bump module versions to
0.2.6.
Reviewed changes
Copilot reviewed 46 out of 46 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| pom.xml | Bump parent version to 0.2.6. |
| assistant-agent-start/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-prompt-builder/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-management/pom.xml | Bump module version; add JUnit Jupiter dependency for new tests. |
| assistant-agent-management/src/main/resources/static/exp-console/index.html | Add References/Assets sections and a “Re-summarize” button in the edit modal. |
| assistant-agent-management/src/main/resources/static/exp-console/app.js | Render references/assets, lazy-load asset content, resummarize references, import as package, and export as zip download. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/spi/SkillExchangeService.java | Add exportSkillPackage(experienceId) SPI method. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/spi/ReferenceSummarizer.java | Introduce SPI for generating reference descriptions (LLM-backed or noop). |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/spi/ExperienceManagementService.java | Add loadAsset and resummarizeReferences for console lazy-load and maintenance. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/model/SkillPackageImportResult.java | Include tool experience IDs/previews and references/assets preview lists in import results. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/model/ExperienceVO.java | Expose references and an asset projection (without raw content by default) to the console. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/SkillPackageParser.java | Parse package.json as structured metadata via Jackson. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/SkillContentClassifier.java | Classify skill package files into references vs assets + assign asset roles. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/RepositoryBackedExperienceManagementService.java | Implement asset loading + reference re-summarization using the summarizer SPI. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/NoopReferenceSummarizer.java | Default summarizer that always returns null (forces fallback descriptions). |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/LlmReferenceSummarizer.java | Spring AI ChatModel-backed reference summarizer implementation. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/InMemorySkillExchangeService.java | Implement package import/export zip, CLI TOOL experience creation, and parallel description generation. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/internal/DescriptionResolver.java | Centralize H1/frontmatter/LLM/fallback description resolution + SHA-256 hashing. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/controller/SkillExchangeController.java | Add GET /export-package/{id} endpoint returning zip bytes with proper headers. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/controller/ExperienceManagementController.java | Add GET /{id}/assets/** and POST /{id}/resummarize endpoints for the console. |
| assistant-agent-management/src/main/java/com/alibaba/assistant/agent/management/config/ExperienceConsoleAutoConfiguration.java | Wire ReferenceSummarizer (LLM if available, else noop) into console services. |
| assistant-agent-management/src/test/java/com/alibaba/assistant/agent/management/internal/SkillPackageParserTest.java | Add test verifying structured package.json metadata parsing. |
| assistant-agent-management/src/test/java/com/alibaba/assistant/agent/management/internal/InMemorySkillExchangeServiceTest.java | Add tests for CLI-bound skill preview/import and references/assets processing. |
| assistant-agent-extensions/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/model/Experience.java | Add references and assets to the domain model for progressive disclosure & sandbox materialization. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/model/ReferenceEntry.java | New model for L3 reference documents (path/mediaType/description/content/hash/size). |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/model/AssetEntry.java | New model for sandbox-only assets (role/content/base64/contentRef/hash/size). |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/model/CliRuntimeConstants.java | Add shared constants for CLI tool naming/IDs and sandbox defaults. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/model/ExperienceArtifact.java | Extend ToolArtifact source docs and add CLI tool-specific fields. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceDisclosurePayloads.java | Add manifest models + ReadExpDocRequest/Response payloads; extend ReadExpResponse. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceDisclosureService.java | Populate manifests in read_exp and implement readDocs for read_exp_doc. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceRuntimeToolStateInterceptor.java | Track read_exp IDs in session state to gate read_exp_doc. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceRuntimeModelInterceptor.java | Register read_exp_doc tool, enforce session gate, and apply max-path limit. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceDisclosurePromptContributor.java | Update prompt guidance to describe L1/L2/L3 disclosure and sandbox asset access. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/config/ExperienceExtensionProperties.java | Add readExpDocMaxPaths configuration. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/experience/config/ExperienceDisclosureAutoConfiguration.java | Wire readExpDocMaxPaths into ExperienceRuntimeModelInterceptor. |
| assistant-agent-extensions/src/test/java/com/alibaba/assistant/agent/extension/experience/disclosure/ExperienceDisclosurePromptContributorTest.java | Add assertions covering new prompt guidance. |
| assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/reply/tools/BaseReplyCodeactTool.java | Ensure empty tool input schema returns valid JSON Schema object instead of {}. |
| assistant-agent-common/src/main/java/com/alibaba/assistant/agent/common/constant/CodeactStateKeys.java | Add session key EXPERIENCE_READ_EXP_IDS used by read_exp_doc gate. |
| assistant-agent-common/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-core/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-core/src/main/java/com/alibaba/assistant/agent/core/executor/GraalCodeExecutor.java | Replace custom escaping with toPythonStringLiteral using JSON serialization + fallback. |
| assistant-agent-core/src/test/java/com/alibaba/assistant/agent/core/executor/GraalCodeExecutorStringLiteralTest.java | Add tests for escaping quotes and multiline strings. |
| assistant-agent-evaluation/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-autoconfigure/pom.xml | Bump module version to 0.2.6. |
| assistant-agent-autoconfigure/src/main/java/com/alibaba/assistant/agent/autoconfigure/tools/WriteCodeTool.java | Strengthen guidance to require complete code in a single call. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| setText('form-label-references', t('referencesLabel')); | ||
| setText('form-label-assets', t('assetsLabel')); |
There was a problem hiding this comment.
applyLocale() calls setText('form-label-references', ...), which sets textContent on the <label> that currently contains the #btn-resummarize button. This will remove the button from the DOM and break the re-summarize feature. Consider moving the label text into a dedicated child element (e.g., a <span id="form-label-references-text">) and only updating that span, or update setText/applyLocale to preserve existing child nodes.
| <label class="form-label" id="form-label-references">References <button type="button" id="btn-resummarize" class="btn btn--ghost" style="margin-left:8px;font-size:12px;padding:2px 8px;">Re-summarize</button></label> | ||
| <div id="form-references-list" class="form-textarea form-textarea--mono" style="min-height:80px;max-height:240px;overflow:auto;padding:8px;white-space:pre-wrap;"></div> |
There was a problem hiding this comment.
#form-label-references contains both the label text and the #btn-resummarize button, but the JS i18n logic updates this label via textContent, which will delete the button node. Split the translatable text into a nested element (e.g. <span ...>) so localization can update text without removing the button.
| public ExperienceRuntimeModelInterceptor(ExperienceDisclosureService experienceDisclosureService, | ||
| ExperienceDisclosureContextResolver contextResolver, | ||
| ExperienceToolInvocationClassifier toolInvocationClassifier) { | ||
| this(experienceDisclosureService, contextResolver, toolInvocationClassifier, 3); | ||
| } |
There was a problem hiding this comment.
The default constructor hard-codes readExpDocMaxPaths to 3, but ExperienceExtensionProperties#readExpDocMaxPaths defaults to 6 and the 4-arg ctor uses 6 as fallback. This can lead to inconsistent limits depending on wiring path (auto-config vs manual/tests). Consider centralizing the default (single constant) or delegating the default ctor to the properties default.
| if (!refPaths.contains(requested)) { | ||
| response.getErrors().add(new ReadExpDocError(requested, | ||
| "unknown path; available references: " + String.join(", ", refPaths))); | ||
| continue; |
There was a problem hiding this comment.
For unknown paths, the error message includes String.join(", ", refPaths). If an experience has many references this can make tool responses very large and slow to serialize/transfer. Consider limiting the returned list (e.g., first N paths + total count) or omitting it from the error entirely.
| ReferenceEntry ref = experience.getReferences().stream() | ||
| .filter(r -> requested.equals(r.getPath())) | ||
| .findFirst() | ||
| .orElse(null); |
There was a problem hiding this comment.
readDocs() does a linear experience.getReferences().stream().findFirst() for each requested path. If there are many references and multiple paths requested, this becomes O(n*m). Consider building a Map<String, ReferenceEntry> once (and reusing it for membership checks + lookup) to keep lookups O(1).
| // 控制台可见的单行概要;正式日志由上层记录。 | ||
| System.out.println("[skill-import] summarize cost=" + elapsed + "ms ok=" + ok + " fail=" + fail | ||
| + " total=" + pending.size()); |
There was a problem hiding this comment.
batchResolveDescriptions writes import telemetry via System.out.println(...). In a server/library module this bypasses the project logging setup and can be noisy/unstructured in production. Use the existing logging framework (SLF4J) or remove the line (and rely on upstream logging) so output can be controlled via log levels/appenders.
| List<ReferenceEntry> references, | ||
| List<AssetEntry> assets, | ||
| Map<String, String> descriptionCache) { | ||
| // SKILL.md 同时保留为 reference(role=skill-md),以便 read_exp_doc 可按 path 检索。 |
There was a problem hiding this comment.
The comment says SKILL.md is kept as a reference with role=skill-md, but ReferenceEntry doesn't have a role field and the code doesn’t set one. This is misleading documentation; either adjust the comment to reflect the actual data model, or add/propagate a role field if downstream logic relies on it.
| // SKILL.md 同时保留为 reference(role=skill-md),以便 read_exp_doc 可按 path 检索。 | |
| // SKILL.md 同时保留为 reference,以便 read_exp_doc 可按 path 检索。 |
| sb.append("经验分为三类:COMMON 用于解释概念/产品术语,REACT 用于提供流程与策略参考,TOOL 用于能力判断、工具选择与调用路径判断。\n"); | ||
| sb.append("披露方式分为两种:`DIRECT` 表示内容已满足高置信短文本条件,可直接利用;`PROGRESSIVE` 表示当前只给候选卡,需要完整正文时调用 `read_exp`。\n"); | ||
| sb.append("渐进披露分三层:L1 候选卡(本块内容) → L2 `read_exp(id)` 返回 content + referenceManifest + assetManifest → L3 `read_exp_doc(id, paths)` 仅按需读取 referenceManifest 中的某些参考文档完整内容。\n"); | ||
| sb.append("调用 `read_exp_doc` 前必须先 `read_exp(id)`,否则会返回错误:\"请先 read_exp(<id>),再 read_exp_doc\";单次最多读取若干个路径,超出会被截断。\n"); |
There was a problem hiding this comment.
Guidance text says when read_exp_doc exceeds the path limit it will be "截断" (truncated), but ExperienceDisclosureService#readDocs returns an error and no documents when paths.size() > maxPaths. Please align the prompt guidance with the actual tool behavior to avoid the model taking an incorrect call pattern.
| sb.append("调用 `read_exp_doc` 前必须先 `read_exp(id)`,否则会返回错误:\"请先 read_exp(<id>),再 read_exp_doc\";单次最多读取若干个路径,超出会被截断。\n"); | |
| sb.append("调用 `read_exp_doc` 前必须先 `read_exp(id)`,否则会返回错误:\"请先 read_exp(<id>),再 read_exp_doc\";单次最多读取若干个路径,超出会返回错误,且不会返回任何文档内容。\n"); |
| showToast(t('toastImportSuccess') || 'Import successful', 'success'); | ||
| closeSkillImport(); |
There was a problem hiding this comment.
toastImportSuccess is not defined in the I18N dictionaries, and t() always returns a non-empty string (falls back to the key), so t('toastImportSuccess') || 'Import successful' will never hit the fallback. This will display the literal key to users. Add a toastImportSuccess entry to both locales (or reuse an existing toast key) and drop the ineffective || fallback.
This pull request introduces significant enhancements to the "experience disclosure" subsystem, improves Python string literal handling, and updates project versions. The main changes include the addition of progressive disclosure APIs and models for experience documents, better guidance and configuration for experience document access, and a safer, more robust approach to Python string literal serialization. Several new tests and configuration options have also been added.
Experience Disclosure Enhancements:
ExperienceDisclosurePayloadsfor progressive disclosure:ReferenceManifestEntry,AssetManifestEntry,ReadExpDocRequest,ReadExpDocResponse,ReadExpDocument, andReadExpDocError, supporting multi-layered experience document access and error reporting. UpdatedReadExpResponseto includereferenceManifestandassetManifestlists. [1] [2]ExperienceDisclosureServiceto populatereferenceManifestandassetManifestinread()responses, and added necessary imports. [1] [2]ExperienceDisclosurePromptContributorto explain progressive disclosure layers and usage ofread_exp_doc, including limitations and correct access patterns.Configuration and State Management:
readExpDocMaxPathsproperty toExperienceExtensionPropertiesto limit the number of paths readable in a singleread_exp_doccall, with corresponding getter/setter and wiring in auto-configuration. [1] [2] [3]EXPERIENCE_READ_EXP_IDSsession state key inCodeactStateKeysfor tracking which experience IDs have been accessed, supporting session-level gating.Python String Literal Handling:
GraalCodeExecutor: replaced custom escaping logic with a robusttoPythonStringLiteralmethod using JSON serialization as the primary approach, with a fallback for error cases. [1] [2]GraalCodeExecutorStringLiteralTestto verify correct escaping of special and multiline strings.Documentation and Guidance:
WRITE_CODE_DESCRIPTIONinWriteCodeToolwith clearer requirements for thecodeargument and best practices for writing complete Python functions in one go.Project Version Updates:
0.2.5to0.2.6across all submodules to reflect ongoing development. [1] [2] [3] [4] [5]