feat(contentunderstanding): Copilot skills for authoring custom analyzers#39137
feat(contentunderstanding): Copilot skills for authoring custom analyzers#39137chienyuanchang wants to merge 19 commits into
Conversation
…nalyzers Add two GitHub Copilot skills under .github/skills/ that guide users through the iterative cycle of authoring custom Content Understanding analyzers in VS Code: - cu-sdk-author-analyzer — single-document-type authoring - cu-sdk-author-analyzer-classify-route — classify-and-route pipelines Both skills delegate to a small cu-skill TypeScript tool under .github/skills/_shared/ that exposes three subcommands (extract-layout, create-and-test, create-and-test-router) and a pure-TypeScript SchemaValidator (no @azure/* deps) so structural mistakes are caught before a service round-trip. Mirrors the .NET skills shipped in Azure/azure-sdk-for-net#60394, the Java skills in Azure/azure-sdk-for-java#49672, and the Python skills in Azure/azure-sdk-for-python#47218. Live-tested against a real CU resource with mixed_financial_docs.pdf: - extract-layout produces .layout.{json,md} - create-and-test reports per-field fill rate + avg confidence and cleans up the analyzer when --ephemeral is set - create-and-test-router creates N inner + 1 outer analyzer, prints a category-aware summary, and cleans up all four New unit tests: - schemaValidator.test.ts (19 cases) using node:test, mirrors Python's test_skills_shared_schema_validator.py, the .NET SkillSchemaValidatorTests.cs, and the Java SchemaValidatorTest.java: valid single-type and classify-route schemas, every rejection path, validateFile error handling, KNOWN_BASE_ANALYZER_IDS allow-list sanity, and a purity guard that fails if the validator source ever pulls in @azure/* or HTTP modules. README: - New 'What's New' section and two new entries in the existing 'GitHub Copilot Skills' table. CHANGELOG: - New 1.2.0-beta.3 (Unreleased) section describing the new skills. Build: - npm install: clean - npm test: 19/19 tests pass The npm tool package is intentionally standalone — not part of any tshy / pnpm workspace, with its own .gitignore for node_modules — so it has zero effect on the published @azure/ai-content-understanding artifact. Bug fix during live test: the JS SDK's typed createAnalyzer serializer reads field.itemDefinition and writes field.items on the wire, while our raw schema files already use the wire shape (items directly). Added a translateForJsSerializer() helper that pre-translates items -> itemDefinition (and $ref -> ref) before passing the schema to the typed client.createAnalyzer(), so array fields no longer have their item definitions stripped.
…ts from Python Three changes for parity with Python PR #47218: 1. **summarizeRouted denominator bug fix** (was a port-time regression). The denominator for a per-field fill rate must be the per-category segment count, NOT the per-field row count. Two segments with one missing the field correctly reports 50% (1/2 segments), not 100% (1/1 rows). This matches Python and .NET; Java was wrong the same way and is being fixed in a parallel commit on the Java PR. 2. **New CLI-helper test files** — createAndTestCommand.test.ts and createAndTestRouterCommand.test.ts. Together they cover the 4 pure-helper tests Python ships (summarize leaf-row flattening, summarizeRouted per-category denominator, summarizeRouted zero-fill, wireInnerIds alias substitution). The denom regression above was discovered by these tests, not a separate review. Python ships 10 CLI-helper tests total; the remaining 6 either test argparse-specific behaviour (`--help` smoke, monkey-patched client) or test code structured differently in JS (error-tuple API), so they don't translate 1:1. We cover the substantive behaviour. 3. **Cross-skill SKILL.md updates** that Python's PR #47218 also shipped: a two-stage-pipeline section + a baseAnalyzerId table in cu-sdk-common-knowledge, 'Next step' cross-refs in cu-sdk-sample-run, and a 'step numbering is contract' callout in cu-sdk-setup.
…r-skills # Conflicts: # sdk/contentunderstanding/ai-content-understanding/CHANGELOG.md
…ygiene) Java CI just caught 'prebuilts' as an unknown word in the same cu-sdk-common-knowledge SKILL.md text we ported from Python. Repro-check found the identical text (3 places in the new SKILL.md, plus 4 pre-existing places in schemaValidator.ts and its test) in the JS package. The JS CI hasn't tripped on it yet, but same lint rule → fix all now before it does. Rephrase as 'prebuilt analyzers'.
Two failures on the last CI run: 1. **Verify-Links** flagged 22 broken sample refs in the two analyzer skill docs. The Python source skills referenced 'samples/*.py' files at the package root; the JS port kept the same shape but JS samples live at 'samples-dev/*.ts' (source-of-truth; 'samples/v1-beta' is generated on release and not stable across releases). Rewrite every '../../../samples/*.ts' -> '../../../samples-dev/*.ts'. All 10 distinct sample files referenced were verified to exist on disk. 2. **Build** failed at cu-skill because TypeScript 6.0.3 (used by the repo) requires explicit 'rootDir' when 'outDir' is set. Our local dev env is on TS 5.7 which infers rootDir from the 'include' glob, so the file compiled locally but failed CI. Add 'rootDir: src' to _shared/tsconfig.json. Local: npm run build succeeds cleanly on TS 6.0.3, 23/23 tests still pass.
…r sources Pure formatting cleanup: prettier re-wraps a couple long function calls and prefers single quotes when the string contains a double quote. No behavior change; the validator diff is line-joining plus quote style, and the test diff is a single line-join and quote-style swap in the purity-guard forbidden list. Verified with 'git diff --ignore-all-space' — 3 bytes of semantic diff per file, both quote-style changes in string literals whose value is identical. 23/23 tests still pass.
The cu-skill authoring tool under sdk/contentunderstanding/ai-content-understanding/.github/skills/_shared/ has its own package.json (so it can be developed as a standalone CLI), but it is not part of the shipping SDK and should not be built as part of turbo build. Without this exclusion, pnpm's 'sdk/**' glob picks up _shared/package.json as a workspace, but its dependencies are not in the top-level lockfile, so CI reports 'not found in lockfile' warnings and then TS2307 errors when turbo tries to build it without any installed node_modules. Scoped narrowly to this package (like the existing '!sdk/identity/identity/integration/**' and '!sdk/servicebus/service-bus/test/stress/**' exclusions).
… template The template comment referenced create_and_test.py — the Python source-of-truth filename copied into the port. In this JS skill, the concrete tool is the cu-skill TypeScript CLI under .github/skills/_shared/, so the template now references the create-and-test skill script and points readers at the tool directory. Same drift being fixed in the parallel .NET (#60394) and Java (#49672) PRs. No functional or public-API change.
Ports the correctness fix from the sibling Java PR (Azure/azure-sdk-for-java#49672, bca631f00b4) to the JS skill. Bug: wireInnerIds keyed the alias lookup on the *category name* instead of on the *analyzerId value*, so a schema like contentCategories: loan_bucket: analyzerId: loan_application silently left the placeholder in place because `aliasToId.has("loan_bucket")` returned false even when `aliasToId.has("loan_application")` was true. The cross-check in runCreateAndTestRouter had the same defect and also rejected valid `prebuilt-*` values (Azure service prebuilts don't need an --inner-schema). New behavior mirrors Python (_patch_outer_analyzer_ids), .NET (WireInnerIds), and Java (WireResult): - Skip categories that omit analyzerId (classification-only "other" bucket). - Skip analyzerId values that start with "prebuilt-" (service prebuilts). - Any other value must match an alias in aliasToId; otherwise return an error naming the missing alias + category. - Every alias in aliasToId must be referenced by some category (typo check); otherwise return an "unused" error. Signature changed from `wireInnerIds(...) -> Record<string, unknown>` to `wireInnerIds(...) -> WireResult` where WireResult carries both patched schema and any errors. Caller in runCreateAndTestRouter now checks errors before proceeding. Test coverage: rewrote wireInnerIdsSubstitutesMatchingAliases with category names deliberately different from analyzerId values, and added: - keeps 'prebuilt-*' analyzerId values as-is - returns error for unknown alias - returns error for unused alias - allows categories without analyzerId Verified: `npm test` in .github/skills/_shared/ passes 27/27 (up from 23).
Revert the pnpm-workspace.yaml exclusion I added in 947c721 (which required @Azure/azure-sdk-js-dev CODEOWNERS review), and instead prevent pnpm from picking up cu-skill as a workspace member by renaming its package.json to package.json.template. The tracked template is copied into place by the skill scripts before `npm install`. Why: - pnpm's `sdk/**` glob only matches literal `package.json`. With the file renamed, the tool directory is not registered as a workspace member, and Turbo does not try to build it during CI. - The tool is still fully runnable: SKILL.md and _shared/README.md install steps now do [ -f package.json ] || cp package.json.template package.json npm install before running the CLI. - The runtime `package.json` is now `.gitignore`d, alongside the existing `node_modules/`, `package-lock.json`, `dist/`, and `.tshy/` entries. This lifts the CODEOWNERS gate on the PR without changing shared repo infrastructure. The alternative (keeping the workspace exclusion) would have required approval from @jeremymeng / @Azure/azure-sdk-js-dev for what is effectively a package-local build-config detail. Verified: `cp package.json.template package.json && npm test` in _shared/ passes 27/27.
There was a problem hiding this comment.
Pull request overview
This PR adds two GitHub Copilot skills under sdk/contentunderstanding/ai-content-understanding/.github/skills/ (cu-sdk-author-analyzer for single-document-type authoring and cu-sdk-author-analyzer-classify-route for mixed-document packets), plus a standalone cu-skill TypeScript CLI tool under .github/skills/_shared/ that backs them. The tool exposes three subcommands (extract-layout, create-and-test, create-and-test-router) wrapping the shipped ContentUnderstandingClient, plus a pure-TypeScript SchemaValidator that catches structural schema mistakes before a service round-trip. It's opt-in tooling — no changes to the published @azure/ai-content-understanding API. This mirrors equivalent skills already shipped for .NET, Java, and Python.
Changes:
- New authoring skills (SKILL.md + JSON templates) that walk users through layout extraction → schema drafting → local validation → batch test → agent review.
- New standalone
cu-skillCLI package (_shared/) with schema validator, client helpers (raw-response capture + serializer translation), three commands, andnode:testunit tests; kept out of the pnpm workspace via apackage.json.template+.gitignorescheme. - README "What's New" + skill-table rows and a
1.2.0-beta.3 (Unreleased)CHANGELOG entry; cross-links added to existingcu-sdk-*skills.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
_shared/src/clientHelpers.ts |
Client builder, raw-response capture policy, JS-serializer key translation (has a broad items-rename bug) |
_shared/src/schemaValidator.ts |
Pure-TS schema validator; no @azure/* imports |
_shared/src/createAndTestCommand.ts |
Single-type create/test/summarize (WARN references a Python sample) |
_shared/src/createAndTestRouterCommand.ts |
Classify-and-route command (unused type import) |
_shared/src/extractLayoutCommand.ts |
Stage-1 layout extraction |
_shared/src/cli.ts |
Subcommand dispatcher |
_shared/src/*.test.ts |
node:test unit tests for validator and pure helpers |
_shared/{tsconfig.json,package.json.template,.gitignore,README.md} |
Standalone tool config/docs |
cu-sdk-author-analyzer/{SKILL.md,templates/schema_template.json} |
Single-type skill + template (DLL/.py/.NET-name/tree carryover issues) |
cu-sdk-author-analyzer-classify-route/{SKILL.md,templates/classifier_template.json} |
Classify-route skill + template (DLL/.py/--schema-dir mismatch issues) |
cu-sdk-{setup,sample-run,common-knowledge}/SKILL.md |
Cross-links and shared field/baseAnalyzerId/classify-route knowledge |
README.md, CHANGELOG.md |
"What's New" section, skill-table rows, 1.2.0-beta.3 entry |
Key findings: one latent bug (translateForJsSerializer rewrites any object key named items, which corrupts a user field literally named items), and several documentation/error-message inconsistencies carried over from the .NET/Python ports (references to a nonexistent sample_update_defaults.py, "built DLL by path", AnalysisResultExtensions.ToLlmInput, a duplicated package.json tree line, and a --schema-dir description that doesn't match the alias logic in the code).
Audit turned up 3 places in the JS port where the Python-source
filename `samples/sample_update_defaults.py` was left in place:
- schema_template.json (`models._comment`)
- classifier_template.json (`models._comment`)
- createAndTestCommand.ts (a user-facing [WARN] on missing
models.completion)
Replaced with `samples-dev/updateDefaults.ts`, which is the actual
JS sample file that configures resource-level model defaults (matching
the link convention already used in the SKILL.md files). Same drift
exists in the sibling .NET and Java PRs and is being fixed there too.
Verified: `npm test` in .github/skills/_shared/ still 27/27 passing.
…LL.md Second audit turned up two more places where .NET-copied wording survived in the JS port. The Prerequisites section in both SKILL.md files said: Required: the `@azure/ai-content-understanding` SDK built locally (the skill tool references the built DLL by path), ... Neither "SDK built locally" nor "built DLL by path" applies to the JS port — the tool is a standalone TypeScript CLI that depends on the published `@azure/ai-content-understanding` package from npm (as _shared/README.md and the install step both already document). The same drift was flagged by the Copilot review on the sibling Java PR (#49672) and got fixed there; JS was missed. Replaced with a JS-appropriate prereq: "Node.js 18+ and npm ... tool depends on the published `@azure/ai-content-understanding` package from npm". Verified: `npm test` in .github/skills/_shared/ still 27/27 passing.
…scriptors Addresses Copilot review comment #1 on PR #39137. Before: translateForJsSerializer walked every object node and renamed any key literally called 'items' to 'itemDefinition' (and '$ref' to 'ref'). Because fieldSchema.fields.<name>, properties.<name>, and itemDefinition.properties.<name> are keyed by user-chosen field names, a schema with a field literally named 'items' — extremely common for line-item arrays — would end up being sent to the service under the name 'itemDefinition' instead. Extraction for that field would silently break. After: the rename is scoped to field-descriptor objects only, detected by the presence of a top-level 'type' string property. Children under fieldSchema.fields / properties / (renamed) itemDefinition.properties are traversed but their own keys are never rewritten. Also exports the helper (as _translateForJsSerializer, underscore- prefixed to mark it test-only) so we can pin down the rules without mocking the Azure client. Test coverage (clientHelpers.test.ts, 6 cases via node:test): - array-field `items` renamed to `itemDefinition` - user field literally named `items` survives untouched - user field literally named `$ref` survives untouched - array-field `$ref` renamed to `ref` - recursion into nested object.properties + array.items - primitives and arrays of primitives pass through unchanged npm test in .github/skills/_shared/: 42/42 passing (was 27/27).
…outer schema Addresses Copilot review comments #7 (schema-dir doc mismatch) and #8 (unused ContentUnderstandingClient import) on PR #39137. Before: --schema-dir did readdirSync(dir).sort() and registered every *.json file under its bare stem as an alias. Given the SKILL.md recommendation to name files invoice_v1.json / invoice_v2.json, that produced aliases like 'invoice_v1' and 'invoice_v2', neither of which matched the 'invoice' category in the outer classifier — the tool failed with 'no --inner-schema entry matches alias invoice' errors. After: --schema-dir now discovers inner schemas the same way Python's _discover_inner_from_dir and .NET's DiscoverInnerFromDir do: 1. Read the outer classifier schema. 2. For every category with a non-'prebuilt-' analyzerId, look for files whose stem is exactly <alias> or starts with '<alias>_'. 3. Pick the alphabetically-last match, so invoice_v2.json beats invoice_v1.json. 4. If any alias has no match, log every missing alias and return null (which surfaces as exit code 2 in runCreateAndTestRouter). This matches the shortcut described in cu-sdk-author-analyzer-classify- route/SKILL.md exactly, keeping the JS behaviour in lockstep with the other three language ports. Also drops the unused 'import type { ContentUnderstandingClient }' at the top of the file — the value flows through buildClient() and the imported service helpers, so the type import was dead code. Test coverage (createAndTestRouterCommand.test.ts, +9 cases): - exact-stem alias resolution - suffix resolution + alphabetical-last tiebreak (v2 > v10 > v1) - exact match vs suffix variants tiebreak pinned - prebuilt-* aliases skipped (no file required) - categories with no analyzerId skipped (classification-only) - missing aliases → null + error message names every missing one - unrelated JSON files in schema-dir ignored - non-string analyzerId tolerated (defensive) - empty contentCategories → empty resolution map npm test in .github/skills/_shared/: 42/42 passing.
…ckage.json in skill tree Addresses Copilot review comments #6, #9, and #10 on PR #39137. cu-sdk-author-analyzer/SKILL.md: - Directory tree listed `package.json` twice (with two different comments). The tracked file is `package.json.template`; the runtime `package.json` is git-ignored and generated on install (see _shared/.gitignore). Collapsed to a single accurate entry. - `AnalysisResultExtensions.ToLlmInput` is the .NET helper name; JS calls it `toLlmInput` and demonstrates it in samples-dev/toLlmInput.ts. Fixed both the name and the broken link (was pointing at samples/ directory instead of the file). cu-sdk-author-analyzer-classify-route/SKILL.md: - Same `AnalysisResultExtensions.ToLlmInput` → `toLlmInput` fix on the classify-route SKILL's output-files section. - Prettier reformatting on tables (column padding), italics (`*x*` → `_x_`), bullets (`*` → `-`), and a multi-line JSON example. No content changes. Skill tool prerequisites text (SKILL.md 'the skill tool references the built DLL by path') was already fixed in c319157, and the sample_update_defaults.py reference was already fixed in 0d5d75c.
…sort
Ports the .NET fix from PR #60394 (commit 61bda1abd16) to keep the
cross-language behaviour in lockstep.
Before: discoverInnerFromDir did '.sort()' on filenames and took the
last element as the 'newest version'. That breaks the moment any
alias reaches double digits: '1' < '9' char-by-char, so
'invoice_v10.json' sorts BEFORE 'invoice_v9.json' — 'alphabetical
last' silently picks v9 and the tool loads the older schema.
After: pick the file with the highest 'version key', defined as:
- group 0 → bare '<alias>.json' (no suffix; oldest)
- group 1 → '<alias>_v<N>.json' or (numeric suffix;
'<alias>_<N>.json' sorted by N)
- group 2 → any other '<alias>_<suffix>.json' (lex tiebreaker)
So invoice_v10 beats invoice_v9 beats invoice, and 'invoice_draft'
still beats bare 'invoice.json' but loses to any versioned file.
Also exports 'versionSortKey' so tests can pin the key extractor
directly (mirrors the .NET pattern where VersionSortKey is internal).
Test updates (createAndTestRouterCommand.test.ts):
- Added 'versionSortKey' describe block (4 cases: group 0 bare,
group 1 numeric with v10>v9, group 1 bare-numeric _42, group 2
non-numeric suffix).
- Replaced 'picks alphabetically-last suffix match (v2 beats v1)'
with 'picks natural version max, so _v10 beats _v9' — the old
test was pinning the exact broken behaviour that Copilot flagged.
- Kept the 'prefers versioned suffix over bare alias baseline' case.
npm test in .github/skills/_shared/: 46/46 passing (was 42; +4
versionSortKey, replaced 1 stale case).
…version sort
The prior SKILL.md description of --schema-dir was still tied to the
old alphabetical sort ("alphabetical sort, so invoice_v2.json wins
over invoice_v1.json"), which was the exact wording Copilot flagged
as inaccurate on PR #39137. After the natural-version-sort fix
(commit d2a463c) the resolution rule changed to 'highest
numeric version wins', so v10 beats v9, not the other way around.
Updated cu-sdk-author-analyzer-classify-route/SKILL.md to spell out
the actual matching rule:
- stem == <alias> (bare baseline, group 0), OR
- stem starts with <alias>_ (versioned; numeric _v<N>/_<N> suffixes
sort by integer N so v10 > v9; non-numeric suffixes fall back to
lexicographic order but still beat the bare baseline).
Also cleaned up the matching in-source comment at the top of
runCreateAndTestRouter in createAndTestRouterCommand.ts, which
described the same stale 'alphabetically-last' rule.
No code change — this is a pure doc fix to keep the SKILL and the
source comments consistent with what the tool actually does now.
npm test in .github/skills/_shared/: 46/46 still passing.
@azure/ai-content-understanding declares engines.node: ">=22.0.0" in its package.json, so users on Node 18-21 hit EBADENGINE warnings on npm install. Update the Prerequisites line and the failure-routing table in both skill files (cu-sdk-author-analyzer and cu-sdk-author-analyzer-classify-route) and cite the engines constraint so the source of truth is discoverable. Also aligns with the repo-wide Node 22 baseline (see .github/skills/node-migration).
…NGELOG section Two internal-consistency follow-ups after the earlier author-analyzer skill fix: 1. cu-sdk-setup/SKILL.md still recommended Node.js 20+ in four places (prereq line, decision table, ASK USER prompt, install-script step 1, troubleshooting row). Bumped all to 22+ so the whole skills family matches @azure/ai-content-understanding's engines.node: ">=22.0.0". 2. CHANGELOG entry moved from '### Features Added' to '### Other Changes' for parity with the Python PR (Azure/azure-sdk-for-python#47218): the Copilot skills are companion tooling, not new SDK API surface, so 'Other Changes' is the more accurate bucket.
feat(contentunderstanding): Copilot skills for authoring custom analyzers
Summary
Adds two GitHub Copilot skills under
sdk/contentunderstanding/ai-content-understanding/.github/skills/that guide users through the iterative cycle of authoring custom Content Understanding analyzers directly inside VS Code:cu-sdk-author-analyzercu-sdk-author-analyzer-classify-routeBoth skills delegate to a small
cu-skillTypeScript tool under.github/skills/_shared/that exposes three subcommands:extract-layout— pulls document structure into.layout.{json,md}so Copilot has ground-truth context for schema drafting.create-and-test— validates a schema locally, creates the analyzer, batch-tests inputs, prints a per-field fill-rate + avg-confidence summary, and (with--ephemeral) cleans up.create-and-test-router— same loop for classify-and-route: creates N inner extractors + 1 outer classifier, wirescontentCategories[*].analyzerId, runs, and prints a category-aware summary.A pure-TypeScript
SchemaValidator(nativenode:fsonly, no@azure/*imports) catches structural mistakes (unknownbaseAnalyzerId, missingfieldSchema, malformedcontentCategoriesroutes) before a service round-trip.This mirrors the .NET skills shipped in Azure/azure-sdk-for-net#60394, the Java skills in Azure/azure-sdk-for-java#49672, and the Python skills in Azure/azure-sdk-for-python#47218.
Live test
Tested against a real CU resource with
mixed_financial_docs.pdf(an invoice + bank statement + loan application):The router variant created 3 inner + 1 outer analyzer, classified 3 segments, extracted all fields, and cleaned up all 4 analyzers (~48 s end-to-end).
What's in the PR
_shared/src/schemaValidator.ts@azure/*deps; purity-guarded by a unit test_shared/src/clientHelpers.ts_shared/src/extractLayoutCommand.ts_shared/src/createAndTestCommand.ts_shared/src/createAndTestRouterCommand.ts_shared/src/cli.ts_shared/src/schemaValidator.test.tsnode:testcases, all passing_shared/package.json+tsconfig.json+.gitignore+README.md.gitignorefornode_modulescu-sdk-author-analyzer/SKILL.md+ templatecu-sdk-author-analyzer-classify-route/SKILL.md+ templateREADME.mdCHANGELOG.mdTest results
Coverage:
analyzerId(catch-all "other" bucket)baseAnalyzerIdrejected (catches theprebuilt-documentAnalyzertypo class)fieldSchemaon non-classifierfieldsobject, unknown fieldtype/methodobject.propertiesandarray.itemsrecursionfieldSchema→ rejectedenableSegment: true→ rejecteddescription→ rejectedvalidateFile: missing file, invalid JSON, valid round-tripvalidateString: invalid JSONKNOWN_BASE_ANALYZER_IDSallow-list sanity checkschemaValidator.tsever pulls in@azure/*/node:http/node:netBugs fixed during live test
.envvalues typically wrap in"…"; rawexportkeeps the quotes. Added areadEnv()helper that strips one layer of surrounding quotes (mirrors the .NET and Java fixes).DefaultAzureCredentialIMDS hang on WSL / dev boxes — built a focusedChainedTokenCredentialchain (EnvironmentCredential→AzureCliCredential) so the IMDS probe doesn't stall on dev boxes (~30 s wait on WSL).items—client.createAnalyzer(id, ContentAnalyzer)runs the schema through a typed serializer that readsfield.itemDefinitionand writesfield.itemson the wire. Our raw schema files use the wire shape (items) directly, so the serializer would strip array-field item definitions and the service returnedInvalidRequest. Fixed with a tinytranslateForJsSerializer()helper that pre-renamesitems→itemDefinition(and$ref→ref) before handing the schema to the typedcreateAnalyzer().{id,status,result,usage}to match Python'spoller.pollUntilDone()output and the .NET / Java skill output.Backward compatibility
No public API changes. The skills tree is opt-in tooling that lives under
.github/skills/and is only loaded by Copilot when a user explicitly asks. Thecu-skillnpm package is standalone — not part of any tshy / pnpm workspace, with its own.gitignoreexcludingnode_modulesandpackage-lock.json— so it doesn't affect normal package builds or the published@azure/ai-content-understandingartifact.Checklist
npm installcleannpm test19/19 passing