import { ExpertGuidance, emptyGuidance } from "std::agents/lib/expertGuidance"
import { llmOptions, withContext } from "std::agents/lib/shared"
import { agencyDocTools, agencyCodeTools } from "std::agents/lib/toolkits"
import { guarded } from "std::decorators"
import { agentSkill } from "std::skills"
import { systemMessage, threadIsNew } from "std::thread"

/** @module
@summary Get Agency syntax guidance and acceptance criteria from the bundled docs.

Use `agencyExpertAgent` before generating Agency source when a task needs
language-specific guidance. Pass `renderGuidance` output as the coding
agent's context, or give the checklist to a verifier. The shared helpers
are in `std::agents/lib/expertGuidance`.
*/

static const skills = agentSkill("agency/expert")

export def buildTools(): any[] {
  """
  Return the Agency expert's documentation and source-checking tools.
  """
  return [...agencyDocTools(), ...agencyCodeTools(), skills]
}

static const systemPrompt = """You are an expert in the Agency programming language, advising a weaker coding agent that is about to attempt the task below.

Return the domain-specific knowledge it needs to get the task right:
- domain: "agency-lang".
- rules: the Agency conventions, syntax rules, and gotchas that apply to this task — the things a non-expert gets wrong. Be concrete and cite the guide.
- checklist: concrete acceptance criteria the finished code must satisfy (compiles/typechecks, uses the right construct, handles failures, etc). For EACH item, state HOW to verify it — the exact command to run (e.g. `agency typecheck <file>`) or the exact construct to look for. Prefer items checkable by running a command.
- ambiguity: if the task allows more than one valid reading, say so, and make the checklist require the work to satisfy the criteria under every reasonable reading, not just the first one.

The bundled docs (docSkill / cliSkill / diagnosticsSkill) are authoritative — consult them rather than guessing. If the task needs no special Agency knowledge, return empty rules and checklist."""

def consult(
  task: string,
  context: string,
  model: string,
  provider: string,
  extraTools: any[],
): ExpertGuidance {
  if (threadIsNew()) {
    systemMessage(systemPrompt)
  }
  // Return position so a model saveDraft propagates as partial guidance.
  return llm(
    "Task:\n${withContext(task: task, context: context)}",
    llmOptions(model: model, provider: provider, tools: buildTools().concat(extraTools).concat([saveDraft])),
  )
}

@guarded(cost: maxCost, time: maxTime)
export def agencyExpertAgent(
  task: string,
  context: string = "",
  maxCost: number = $10.00,
  maxTime: number = 10m,
  model: string = "",
  provider: string = "",
  session: string = "",
  extraTools: any[] = [],
): Result<ExpertGuidance> {
  """
  Consult an Agency-language specialist: return the syntax rules and
  acceptance checklist a solver needs, grounded in the bundled docs.

  @param task - The task to advise on
  @param context - Extra material, or ""
  @param maxCost - Cost budget in USD.
  @param maxTime - Time budget in milliseconds.
  @param model - Model override, or "" for the ambient model
  @param provider - Provider for the model override, ignored when model is empty.
  @param session - Session name to share a thread across calls, or "" for isolated
  @param extraTools - Extra tools to offer the LLM, appended to the built-in set
  """
  thread(label: "agencyExpertAgent", session: session) {
    return consult(
      task: task,
      context: context,
      model: model,
      provider: provider,
      extraTools: extraTools,
    )
  }
}
