Skip to content
30 changes: 19 additions & 11 deletions solutions/ess-maker-skills/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@
## MANDATORY FIRST ACTION — Do This Before Anything Else

**YOUR VERY FIRST ACTION on every new conversation must be: use your file
reading tool to try to read `.local/setup/config.json`.**
reading tool to read `.local/setup/config.json`.**
Do NOT skip this step. Do NOT respond to the user's message first. Do NOT greet
the user first. Do NOT list capabilities. Read this file FIRST, then decide what
to do based on the result.
the user first. Do NOT list capabilities. Read this file FIRST, then decide
what to do based on the result.

### If setup is missing or not ready

DA setup is ready only when `.local/setup/config.json` has `schema_version`
equal to `4` and its `agents` entry matching `.local/config.json`'s
`activeAgent` workspace slug has `connect_ready` equal to `true`. Setup writes
that per-agent marker only after all eight foundation steps for that agent have
reached `done`.
DA authoring setup is ready when `.local/setup/config.json` has
`schema_version` equal to `4` and at least one entry in its `agents` object has
`authoring_ready` equal to `true`. This is the only readiness marker used by
this first gate. Ignore `connect_ready`, `active_step`, blocked capacity, and
blocked connection steps here: they describe runtime readiness after the exact
editable agent and local workspace are already usable, and `/connect` exists
to resolve a missing connection.

This first gate establishes only that the workspace has a usable DA foundation.
After it passes, read `.local/config.json` and let the invoked command resolve
and validate the exact active agent. If operational configuration is missing or
does not match a canonical setup entry, report that configuration error instead
of routing back to `/setup`.

**STOP.** Do not read any skill files. Do not load templates. Do not search for
files. Do not attempt any customization work. Do not answer questions about ESS.
Expand Down Expand Up @@ -212,9 +220,9 @@ After canonical DA setup is complete:
available;
- Dataverse push and server-backed validation are permitted in this
workspace; run the push pipeline when the maker asks to push local changes;
- `/connect workday` uses the checked-in ESS DA HR Workday extension guidance;
unsupported products or agent verticals must stop at their explicit routing
boundary;
- `/connect servicenow` is available for the DA-GA HR prototype through its
product-specific guidance; other integrations require their corresponding
DA-GA product extension guidance;
- `/backup-template-configs` and `/restore-template-configs` are no longer
supported because they belonged to the retired Dataverse-based agent model;
- `/flightcheck` may run only its local-files scope.
Expand Down
32 changes: 23 additions & 9 deletions solutions/ess-maker-skills/.github/prompts/connect.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ description: "Connect Workday or another supported integration"
# Connect

**Setup-state check.** Read `.local/setup/config.json` and `.local/config.json`.
Resolve `activeAgent` to the canonical agent whose `agent.workspace_slug`
matches. Continue when canonical state has `schema_version: 4`, complete
workspace evidence, and `steps.SETUP-07.state: "done"`. Do not require
`connect_ready: true`; this command configures the product-extension
connections that may currently block runtime readiness. If local workspace
materialization is incomplete, show:
Resolve `.local/config.json`'s `activeAgent` slug to the matching object in its
`agents` array, then use that object's `botId` to select the entry in
`.local/setup/config.json`'s `agents` object. Continue when canonical state has
`schema_version: 4`, that agent has `authoring_ready: true`, complete workspace evidence,
and `steps.SETUP-07.state: "done"`. Do not require
`connect_ready: true`; Ignore `connect_ready`, `active_step`, blocked capacity,
and blocked connection steps for this admission check because this command
configures the product-extension connections that may currently block runtime
readiness. If local workspace materialization is incomplete, show:

> Welcome to the ESS Maker Kit. Before running `/connect`, type `/setup` to set up your environment.

Expand All @@ -30,7 +33,18 @@ Rules:
3. The ONLY text the user sees is Message blocks and tool output tables.
4. Do not compose your own messages. If there is no Message block for a
situation, stay silent and proceed to the next action.
5. For resumable product-specific connect flows, inspect current live and
durable status before every step. Skip completed steps with the skill's
defined skip message instead of repeating their question or operation, but
only when current completion is API-verifiable or proven by a successful
kit operation. Always ask the maker to confirm steps whose current state
cannot be verified through an available API.
6. Waiting for maker input or a portal update is not task completion. Keep the
current question as the resume point, never treat an unavailable-user
auto-response as an answer, and never require the maker to invoke
`/connect` again merely to continue that question.
Comment thread
DapheneShao marked this conversation as resolved.

After reading SKILL.md, your first action is to check for
`.local/connect/steps.md`. If starting fresh, your first message to the user
is the checklist table from the Fresh Start section.
Do not inspect `.local/connect/steps.md` before the router selects a path. If
the router selects the retained Preview path, use that path's persisted
`steps.md` and Fresh Start contract. If it selects the DA ServiceNow path,
start with that skill's live `inspect` contract instead.
30 changes: 29 additions & 1 deletion solutions/ess-maker-skills/scripts/agentbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,14 @@ def _acquire_token(
token = result.get("access_token") if result else None
if not token:
error = result.get("error", "unknown_error") if result else "unknown_error"
description = (
str(result.get("error_description", "")).strip()
if result
else ""
)
detail = f": {description}" if description else ""
raise AgentBuilderError(
f"AgentBuilder authentication failed ({error})."
f"AgentBuilder authentication failed ({error}){detail}"
)
if cache.has_state_changed:
_persist_token_cache(cache, cache_path)
Expand All @@ -507,6 +513,7 @@ def authenticate(
cache_path: Path = DEFAULT_TOKEN_CACHE,
force_account_selection: bool = False,
account_hint: str | None = None,
scopes: tuple[str, ...] | None = None,
) -> str:
"""Acquire an ESS ADK delegated token without contacting Dataverse."""
try:
Expand All @@ -520,6 +527,7 @@ def authenticate(
cache_path=cache_path,
force_account_selection=force_account_selection,
account_hint=account_hint,
scopes=scopes,
)


Expand Down Expand Up @@ -887,6 +895,26 @@ def fetch_components(self, agent_id: str) -> dict[str, Any]:
raise AgentBuilderError("Component fetch returned an invalid shape.")
return body

def update_components(
self,
agent_id: str,
change_set: dict[str, Any],
) -> dict[str, Any]:
"""Apply one caller-supplied MinimalBot component change set."""
if not isinstance(change_set, dict):
raise ValueError("Component change set must be a JSON object.")
body = self._json(
"PUT",
f"/copilotstudio/minimalBots/api/{agent_id}/components",
"Component update",
params={"api-version": NATIVE_ALM_API_VERSION},
body=change_set,
timeout=180,
)
if not isinstance(body, dict):
raise AgentBuilderError("Component update returned an invalid shape.")
return body

def update_bot_entity(
self,
agent_id: str,
Expand Down
Loading
Loading