@mrclrchtr/supi-prompt-suggestions 7.1.0 → 7.1.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/README.md CHANGED
@@ -18,6 +18,8 @@ Advisory ghost-text prompt suggestions for the [pi coding agent](https://github.
18
18
 
19
19
  ## Install
20
20
 
21
+ Requires Pi 0.86.0 or later.
22
+
21
23
  ```bash
22
24
  pi install npm:@mrclrchtr/supi-prompt-suggestions
23
25
  ```
@@ -53,8 +55,8 @@ The default is `disabled`. Pick a cheap, fast model if you want lightweight sugg
53
55
 
54
56
  Settings follow SuPi's normal scoped config behavior: set a global default, then override it per project when needed.
55
57
 
56
- Suggestion requests use PI's model registry. PI owns authentication and provider routing; the
57
- extension does not resolve or copy credentials.
58
+ Suggestion requests use PI's registry simple-completion path. PI owns authentication, provider
59
+ routing, and context-aware output limits; the extension does not resolve or copy credentials.
58
60
 
59
61
  ## Privacy
60
62
 
@@ -51,10 +51,11 @@ Config file locations:
51
51
 
52
52
  ### Model requests
53
53
 
54
- - `completeModelRequest(ctx, model, context, options)` — complete through PI's model registry with stable feature affinity. PI owns auth and endpoint resolution.
54
+ - `completeModelRequest(ctx, model, context, options)` — send API-specific options through PI's model registry.
55
+ - `completeSimpleModelRequest(ctx, model, context, options)` — send provider-neutral options through `streamSimple().result()` on PI 0.86.0 or later. PI supplies model-derived output limits and context guards.
55
56
  - `callWithJsonResponse()` — retry a registry request, extract JSON, and validate it with TypeBox.
56
57
 
57
- `completeModelRequest()` requires a stable `affinityScope`. It keeps cache retention defaults, does not include prompt content in the affinity ID, and adds OpenCode headers only when the provider or exact model endpoint matches OpenCode. Pass `maxTokens: model.maxTokens` when a caller needs the model's declared output cap without using PI private modules.
58
+ Both completion helpers require a stable `affinityScope`. PI owns auth and endpoint resolution. The helpers keep cache retention defaults, exclude prompt content from the affinity ID, and add OpenCode headers only when the provider or exact model endpoint matches OpenCode. Use the simple helper when PI should manage output limits; the API-specific helper forwards the caller's limit unchanged.
58
59
 
59
60
  ### Shared registries
60
61
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "7.1.0",
3
+ "version": "7.1.1",
4
4
  "description": "Shared settings, configuration, reporting, and session infrastructure",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -5,6 +5,7 @@ import type {
5
5
  Context,
6
6
  Model,
7
7
  ModelsApiStreamOptions,
8
+ ModelsSimpleStreamOptions,
8
9
  ProviderHeaders,
9
10
  } from "@earendil-works/pi-ai";
10
11
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
@@ -18,16 +19,7 @@ import { Value } from "typebox/value";
18
19
 
19
20
  const MODEL_REQUEST_NAMESPACE = "supi-direct-model-request-v1";
20
21
 
21
- /**
22
- * Options for {@link completeModelRequest}.
23
- *
24
- * Authentication, provider environment, and session identity stay under PI
25
- * control. The feature supplies a stable scope for its prompt stream.
26
- */
27
- export type CompleteModelRequestOptions<TApi extends Api = Api> = Omit<
28
- ModelsApiStreamOptions<TApi>,
29
- "apiKey" | "env" | "sessionId"
30
- > & {
22
+ type ModelRequestOptions<T> = Omit<T, "apiKey" | "env" | "sessionId"> & {
31
23
  /** Stable feature scope. Do not include prompt, turn, or retry data. */
32
24
  affinityScope: string;
33
25
  /** PI owns these fields, including for APIs with open-ended option types. */
@@ -36,6 +28,14 @@ export type CompleteModelRequestOptions<TApi extends Api = Api> = Omit<
36
28
  sessionId?: never;
37
29
  };
38
30
 
31
+ /** API-specific completion options. PI owns auth, environment, and identity. */
32
+ export type CompleteModelRequestOptions<TApi extends Api = Api> = ModelRequestOptions<
33
+ ModelsApiStreamOptions<TApi>
34
+ >;
35
+
36
+ /** Provider-neutral completion options. PI owns auth, environment, and identity. */
37
+ export type CompleteSimpleModelRequestOptions = ModelRequestOptions<ModelsSimpleStreamOptions>;
38
+
39
39
  function createModelRequestAffinityId(
40
40
  sessionId: string,
41
41
  affinityScope: string,
@@ -84,24 +84,10 @@ function addOpenCodeDefaultHeaders(
84
84
  return result;
85
85
  }
86
86
 
87
- /**
88
- * Complete a direct request through PI's model registry.
89
- *
90
- * PI resolves authentication, provider headers, environment, and the
91
- * effective endpoint. This helper adds one stable opaque session identity for
92
- * the feature prompt stream and applies the OpenCode compatibility defaults.
93
- * It does not retry, validate output, or present errors.
94
- *
95
- * When `maxTokens` is omitted, the underlying registry receives no explicit
96
- * output cap. A caller that needs the selected model's declared cap can pass
97
- * `maxTokens: model.maxTokens` without importing PI internals.
98
- */
99
- export async function completeModelRequest<TApi extends Api>(
100
- ctx: ExtensionContext,
101
- model: Model<TApi>,
102
- context: Context,
103
- options: CompleteModelRequestOptions<TApi>,
104
- ): Promise<AssistantMessage> {
87
+ /** Keep request identity and header policy identical for both completion paths. */
88
+ function prepareModelRequestOptions<
89
+ T extends Pick<ModelsSimpleStreamOptions, "signal" | "transformHeaders">,
90
+ >(ctx: ExtensionContext, model: Model<Api>, options: ModelRequestOptions<T>): T {
105
91
  const { affinityScope, transformHeaders: callerTransformHeaders, ...requestOptions } = options;
106
92
  const safeRequestOptions = { ...requestOptions };
107
93
  delete safeRequestOptions.apiKey;
@@ -118,13 +104,57 @@ export async function completeModelRequest<TApi extends Api>(
118
104
  return addOpenCodeDefaultHeaders(model, affinityId, transformed);
119
105
  };
120
106
 
121
- // Restore PI's conditional provider-option type after removing owned fields.
122
- return ctx.modelRegistry.complete(model, context, {
107
+ // Restore PI's option type after removing owned fields.
108
+ return {
123
109
  ...safeRequestOptions,
124
110
  signal: safeRequestOptions.signal ?? ctx.signal,
125
111
  sessionId: affinityId,
126
112
  transformHeaders,
127
- } as unknown as ModelsApiStreamOptions<TApi>);
113
+ } as unknown as T;
114
+ }
115
+
116
+ /**
117
+ * Complete an API-specific request through PI's model registry.
118
+ *
119
+ * PI resolves auth, headers, environment, and the effective endpoint. SuPi adds
120
+ * a stable opaque feature identity and OpenCode header defaults. This helper
121
+ * does not retry, validate output, or present errors. It supplies no output cap
122
+ * when `maxTokens` is omitted; use {@link completeSimpleModelRequest} for PI's
123
+ * model-derived defaults and context-aware limits.
124
+ */
125
+ export async function completeModelRequest<TApi extends Api>(
126
+ ctx: ExtensionContext,
127
+ model: Model<TApi>,
128
+ context: Context,
129
+ options: CompleteModelRequestOptions<TApi>,
130
+ ): Promise<AssistantMessage> {
131
+ return ctx.modelRegistry.complete(
132
+ model,
133
+ context,
134
+ prepareModelRequestOptions<ModelsApiStreamOptions<TApi>>(ctx, model, options),
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Complete a provider-neutral request through PI's registry simple path.
140
+ *
141
+ * Requires PI 0.86.0 or later. PI's provider handles simple options, including
142
+ * model-derived output limits and context estimates. Request identity, header
143
+ * policy, and error behavior match {@link completeModelRequest}.
144
+ */
145
+ export async function completeSimpleModelRequest(
146
+ ctx: ExtensionContext,
147
+ model: Model<Api>,
148
+ context: Context,
149
+ options: CompleteSimpleModelRequestOptions,
150
+ ): Promise<AssistantMessage> {
151
+ return ctx.modelRegistry
152
+ .streamSimple(
153
+ model,
154
+ context,
155
+ prepareModelRequestOptions<ModelsSimpleStreamOptions>(ctx, model, options),
156
+ )
157
+ .result();
128
158
  }
129
159
 
130
160
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-prompt-suggestions",
3
- "version": "7.1.0",
3
+ "version": "7.1.1",
4
4
  "description": "Optional model-powered ghost-text prompt suggestions",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "video": "https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-prompt-suggestions/assets/demo.mp4"
49
49
  },
50
50
  "dependencies": {
51
- "@mrclrchtr/supi-core": "7.1.0"
51
+ "@mrclrchtr/supi-core": "7.1.1"
52
52
  },
53
53
  "bundledDependencies": [
54
54
  "@mrclrchtr/supi-core"
@@ -1,9 +1,8 @@
1
1
  /** Low-level suggestion model client. */
2
2
 
3
3
  import type { Api, Context, Model } from "@earendil-works/pi-ai";
4
- import { clampMaxTokensToContext } from "@earendil-works/pi-ai/api/simple-options";
5
4
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
6
- import { completeModelRequest } from "@mrclrchtr/supi-core/llm";
5
+ import { completeSimpleModelRequest } from "@mrclrchtr/supi-core/llm";
7
6
  import {
8
7
  classifySuggestionFailure,
9
8
  createSuggestionFailure,
@@ -69,7 +68,7 @@ export interface SuggestionClientOptions {
69
68
  * Call the suggestion model through PI's model registry.
70
69
  *
71
70
  * The request keeps the fixed prompt and bounded assistant tail. PI resolves
72
- * authentication, endpoint, headers, and provider environment.
71
+ * authentication, endpoint, headers, provider environment, and simple output limits.
73
72
  */
74
73
  export async function callSuggestionModel(
75
74
  opts: SuggestionClientOptions,
@@ -86,10 +85,9 @@ export async function callSuggestionModel(
86
85
  };
87
86
 
88
87
  try {
89
- const response = await completeModelRequest(opts.ctx, opts.model, context, {
88
+ const response = await completeSimpleModelRequest(opts.ctx, opts.model, context, {
90
89
  affinityScope: "prompt-suggestions",
91
90
  signal: opts.signal,
92
- maxTokens: clampMaxTokensToContext(opts.model, context, opts.model.maxTokens),
93
91
  });
94
92
 
95
93
  if (response.stopReason === "aborted") {