pi-para 0.6.1 → 0.6.3

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.
@@ -90,7 +90,7 @@ export function enqueueCompletedSessions(
90
90
  }
91
91
 
92
92
  export function createCaptureSessionHandler(deps: CaptureSessionDeps): SchedulerTaskHandler {
93
- return async (item: QueueItem) => {
93
+ return async (item: QueueItem, scheduler: WikiScheduler) => {
94
94
  const payload = item.payload as CaptureSessionPayload;
95
95
  if (!payload.sessionPath) throw new Error("capture-session payload missing sessionPath");
96
96
  if (!existsSync(payload.sessionPath)) throw new Error(`Session file not found: ${payload.sessionPath}`);
@@ -111,6 +111,14 @@ export function createCaptureSessionHandler(deps: CaptureSessionDeps): Scheduler
111
111
  stateDb.recordSuccess(payload.sessionPath, scope, [], []);
112
112
  } else {
113
113
  stateDb.recordSuccess(payload.sessionPath, scope, result.pagesCreated, result.pagesUpdated);
114
+ // Capture writes pages through processSession, which reindexes BM25
115
+ // inline but never embeds. Chain a deduplicated qmd-embed task so the
116
+ // new pages become vector-searchable without waiting for the next
117
+ // session startup drain. Enqueued on the same scheduler, so the
118
+ // surrounding tick loop claims it right after this task completes.
119
+ if (scheduler.embedEnabled && result.pagesCreated.length + result.pagesUpdated.length > 0) {
120
+ scheduler.enqueue("qmd-embed", {}, { dedupeKey: "qmd-embed", priority: 5 });
121
+ }
114
122
  }
115
123
  } catch (err) {
116
124
  const message = err instanceof Error ? err.message : String(err);
package/src/settings.ts CHANGED
@@ -120,6 +120,94 @@ export function disableRerank(config: ParaUserConfig): void {
120
120
  config.qmd.rerank = null;
121
121
  }
122
122
 
123
+ // -- Provider presets ---------------------------------------------------------
124
+
125
+ /** Known API providers selectable in /wiki-settings (baseUrl + format prefilled). */
126
+ export interface ProviderPreset {
127
+ id: string;
128
+ label: string;
129
+ baseUrl: string;
130
+ apiFormat: "openai" | "anthropic";
131
+ defaultEmbedModel?: string;
132
+ defaultRerankModel?: string;
133
+ }
134
+
135
+ export const PROVIDER_PRESETS: ProviderPreset[] = [
136
+ {
137
+ id: "openai",
138
+ label: "OpenAI",
139
+ baseUrl: "https://api.openai.com/v1",
140
+ apiFormat: "openai",
141
+ defaultEmbedModel: "text-embedding-3-small",
142
+ },
143
+ {
144
+ id: "openrouter",
145
+ label: "OpenRouter",
146
+ baseUrl: "https://openrouter.ai/api/v1",
147
+ apiFormat: "openai",
148
+ defaultEmbedModel: "openai/text-embedding-3-small",
149
+ },
150
+ {
151
+ id: "gemini",
152
+ label: "Google Gemini (OpenAI-compatible)",
153
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
154
+ apiFormat: "openai",
155
+ defaultEmbedModel: "text-embedding-004",
156
+ },
157
+ {
158
+ id: "mistral",
159
+ label: "Mistral",
160
+ baseUrl: "https://api.mistral.ai/v1",
161
+ apiFormat: "openai",
162
+ defaultEmbedModel: "mistral-embed",
163
+ },
164
+ {
165
+ id: "voyage",
166
+ label: "Voyage AI",
167
+ baseUrl: "https://api.voyageai.com/v1",
168
+ apiFormat: "openai",
169
+ defaultEmbedModel: "voyage-3-lite",
170
+ defaultRerankModel: "rerank-2-lite",
171
+ },
172
+ {
173
+ id: "jina",
174
+ label: "Jina AI",
175
+ baseUrl: "https://api.jina.ai/v1",
176
+ apiFormat: "openai",
177
+ defaultEmbedModel: "jina-embeddings-v3",
178
+ defaultRerankModel: "jina-reranker-v2-base-multilingual",
179
+ },
180
+ {
181
+ id: "ollama",
182
+ label: "Ollama (local server)",
183
+ baseUrl: "http://127.0.0.1:11434/v1",
184
+ apiFormat: "openai",
185
+ defaultEmbedModel: "nomic-embed-text",
186
+ },
187
+ ];
188
+
189
+ export function findProviderPreset(id: string): ProviderPreset | undefined {
190
+ return PROVIDER_PRESETS.find((p) => p.id === id);
191
+ }
192
+
193
+ /**
194
+ * Apply a provider preset to an embedding/rerank profile: sets provider,
195
+ * baseUrl, apiFormat, and the preset's default model for the profile kind.
196
+ * Leaves credentialRef and dims untouched (dims must match any existing
197
+ * vector index; credential wiring is a separate explicit step).
198
+ */
199
+ export function applyProviderPreset(
200
+ profile: ProviderCredentialRef,
201
+ preset: ProviderPreset,
202
+ kind: "embedding" | "rerank",
203
+ ): void {
204
+ profile.provider = preset.id;
205
+ profile.baseUrl = preset.baseUrl;
206
+ profile.apiFormat = preset.apiFormat;
207
+ const model = kind === "embedding" ? preset.defaultEmbedModel : preset.defaultRerankModel;
208
+ if (model) profile.model = model;
209
+ }
210
+
123
211
  function parsePositiveInteger(value: string, fallback: number): number {
124
212
  const parsed = parseInt(value, 10);
125
213
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
package/src/setup.ts CHANGED
@@ -79,7 +79,7 @@ export function formatSetupResult(result: SetupResult): string {
79
79
  const lines = [`pi-para setup ${result.dryRun ? "dry run " : ""}complete.`];
80
80
  for (const change of result.changes) lines.push(` ✓ ${change}`);
81
81
  for (const warning of result.warnings) lines.push(` ⚠ ${warning}`);
82
- lines.push("", "Next: restart open Pi sessions, then run /wiki or pi-para doctor.");
82
+ lines.push("", "Next: restart open Pi sessions, then run /wiki or `npx -y pi-para@latest doctor`.");
83
83
  return lines.join("\n");
84
84
  }
85
85