ahead-pi 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ahead-pi",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "AHEAD workflow enforcement and context for Pi",
5
5
  "keywords": [
6
6
  "ahead",
package/src/examples.ts CHANGED
@@ -8,7 +8,14 @@ export interface FieldExamplesInput {
8
8
  fields: string[];
9
9
  }
10
10
 
11
- const EXAMPLES_TIMEOUT_MS = 25_000;
11
+ const EXAMPLES_TIMEOUT_MS = 12_000;
12
+
13
+ export type FieldExamplesSkipped = "no-model" | "no-auth" | "failed";
14
+
15
+ export interface FieldExamplesResult {
16
+ examples?: string[][];
17
+ skipped?: FieldExamplesSkipped;
18
+ }
12
19
 
13
20
  /**
14
21
  * Draft two inspiration-only example lines per artifact field.
@@ -21,10 +28,10 @@ const EXAMPLES_TIMEOUT_MS = 25_000;
21
28
  export async function draftFieldExamples(
22
29
  ctx: ExtensionCommandContext,
23
30
  input: FieldExamplesInput,
24
- ): Promise<string[][] | undefined> {
31
+ ): Promise<FieldExamplesResult> {
25
32
  const model = ctx.model;
26
33
  if (!model) {
27
- return undefined;
34
+ return { skipped: "no-model" };
28
35
  }
29
36
 
30
37
  const prompt = [
@@ -46,9 +53,13 @@ export async function draftFieldExamples(
46
53
  ].join("\n");
47
54
 
48
55
  try {
56
+ // getProviderAuth returning undefined means no usable credential of any
57
+ // kind could be resolved — only then is a heads-up accurate. A resolved
58
+ // auth object without an apiKey (e.g. OAuth) may still succeed through
59
+ // the adapter's own credential resolution, so we attempt the call.
49
60
  const auth = await ctx.modelRegistry.getProviderAuth(model.provider);
50
61
  if (!auth) {
51
- return undefined;
62
+ return { skipped: "no-auth" };
52
63
  }
53
64
  const message = await Promise.race([
54
65
  completeSimple(
@@ -74,11 +85,15 @@ export async function draftFieldExamples(
74
85
  }),
75
86
  ]);
76
87
  if (!message) {
77
- return undefined;
88
+ return { skipped: "failed" };
89
+ }
90
+ const examples = parseExampleLines(message, input.fields.length);
91
+ if (!examples) {
92
+ return { skipped: "failed" };
78
93
  }
79
- return parseExampleLines(message, input.fields.length);
94
+ return { examples };
80
95
  } catch {
81
- return undefined;
96
+ return { skipped: "failed" };
82
97
  }
83
98
  }
84
99
 
@@ -99,7 +114,8 @@ function textBlocks(content: unknown): string[] {
99
114
  return blocks;
100
115
  }
101
116
 
102
- function parseExampleLines(message: unknown, fieldCount: number): string[][] | undefined {
117
+ /** Exported for unit testing; the wire shape is validated defensively at runtime. */
118
+ export function parseExampleLines(message: unknown, fieldCount: number): string[][] | undefined {
103
119
  const text = textBlocks(isRecord(message) ? message.content : undefined).join("\n");
104
120
 
105
121
  const perField: string[][] = Array.from({ length: fieldCount }, () => []);
package/src/index.ts CHANGED
@@ -1603,15 +1603,27 @@ async function recordHumanArtifact(
1603
1603
  const prompts = promptsForArtifact(state.workflow_id, state.phase.id, artifact.kind);
1604
1604
  let template = await humanArtifactTemplate(store, state, run, artifact.kind, artifact.title);
1605
1605
  if (ctx.hasUI && artifact.kind !== "review-disposition" && prompts.length > 0) {
1606
- const examples = await draftFieldExamples(ctx, {
1606
+ if (ctx.model) {
1607
+ ctx.ui.notify("Drafting two example prompts per field (inspiration only)…", "info");
1608
+ }
1609
+ const draft = await draftFieldExamples(ctx, {
1607
1610
  workflowTitle: engine.getWorkflow(state.workflow_id).title,
1608
1611
  phaseTitle: state.phase.title,
1609
1612
  runTitle: run.title,
1610
1613
  fields: prompts,
1611
1614
  });
1612
- if (examples) {
1613
- template = insertFieldExamples(template, examples);
1615
+ if (draft.examples) {
1616
+ template = insertFieldExamples(template, draft.examples);
1617
+ } else if (draft.skipped === "no-auth") {
1618
+ ctx.ui.notify(
1619
+ "Example prompts unavailable: no usable model credential could be resolved for this session.",
1620
+ "info",
1621
+ );
1622
+ } else if (draft.skipped === "no-model") {
1623
+ ctx.ui.notify("Example prompts unavailable: no active model in this session.", "info");
1614
1624
  }
1625
+ // "failed" (timeout, unparseable output, transient error) stays silent:
1626
+ // the plain template is the fallback and needs no apology.
1615
1627
  }
1616
1628
  let content = await ctx.ui.editor(
1617
1629
  `AHEAD mode · ${artifact.title} · write in your own words`,