@oh-my-pi/pi-ai 16.1.22 → 16.2.0

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/types/auth-broker/wire-schemas.d.ts +5 -0
  3. package/dist/types/index.d.ts +2 -0
  4. package/dist/types/providers/anthropic-messages-server-schema.d.ts +31 -0
  5. package/dist/types/providers/gitlab-duo-workflow.d.ts +254 -0
  6. package/dist/types/providers/openai-shared.d.ts +3 -1
  7. package/dist/types/registry/api-key-login.d.ts +1 -0
  8. package/dist/types/registry/api-key-validation.d.ts +1 -0
  9. package/dist/types/registry/coreweave.d.ts +7 -0
  10. package/dist/types/registry/gitlab-duo-workflow.d.ts +10 -0
  11. package/dist/types/registry/gitlab-duo.d.ts +1 -1
  12. package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +6 -0
  13. package/dist/types/registry/registry.d.ts +13 -1
  14. package/dist/types/stream.d.ts +8 -0
  15. package/dist/types/types.d.ts +12 -0
  16. package/dist/types/usage/ollama.d.ts +5 -0
  17. package/dist/types/usage/openai-codex-base-url.d.ts +1 -0
  18. package/dist/types/usage/openai-codex.d.ts +0 -1
  19. package/dist/types/usage.d.ts +33 -0
  20. package/dist/types/utils/thinking-loop.d.ts +46 -0
  21. package/package.json +4 -4
  22. package/src/api-registry.ts +1 -0
  23. package/src/auth-broker/wire-schemas.ts +7 -0
  24. package/src/auth-storage.ts +15 -2
  25. package/src/dialect/anthropic.md +2 -2
  26. package/src/dialect/anthropic.ts +1 -1
  27. package/src/dialect/deepseek.md +2 -1
  28. package/src/dialect/deepseek.ts +1 -1
  29. package/src/dialect/gemini.md +2 -1
  30. package/src/dialect/gemma.md +2 -1
  31. package/src/dialect/glm.md +2 -2
  32. package/src/dialect/harmony.md +2 -1
  33. package/src/dialect/harmony.ts +1 -1
  34. package/src/dialect/hermes.md +2 -1
  35. package/src/dialect/hermes.ts +1 -1
  36. package/src/dialect/kimi.md +2 -1
  37. package/src/dialect/kimi.ts +1 -1
  38. package/src/dialect/minimax.md +2 -2
  39. package/src/dialect/pi.md +1 -1
  40. package/src/dialect/qwen3.md +2 -1
  41. package/src/dialect/qwen3.ts +1 -1
  42. package/src/dialect/xml.md +2 -2
  43. package/src/index.ts +2 -0
  44. package/src/providers/amazon-bedrock.ts +8 -2
  45. package/src/providers/anthropic-messages-server-schema.ts +6 -1
  46. package/src/providers/anthropic.ts +2 -1
  47. package/src/providers/cursor.ts +7 -2
  48. package/src/providers/devin.ts +1 -2
  49. package/src/providers/gitlab-duo-workflow-chatml-note.md +1 -0
  50. package/src/providers/gitlab-duo-workflow.ts +3038 -0
  51. package/src/providers/ollama.ts +1 -2
  52. package/src/providers/openai-codex-responses.ts +1 -1
  53. package/src/providers/openai-completions.ts +8 -2
  54. package/src/providers/openai-shared.ts +76 -4
  55. package/src/registry/api-key-login.ts +2 -0
  56. package/src/registry/api-key-validation.ts +8 -0
  57. package/src/registry/coreweave.ts +38 -0
  58. package/src/registry/gitlab-duo-workflow.ts +20 -0
  59. package/src/registry/gitlab-duo.ts +1 -1
  60. package/src/registry/oauth/gitlab-duo-workflow.ts +134 -0
  61. package/src/registry/oauth/oauth.html +177 -59
  62. package/src/registry/registry.ts +4 -0
  63. package/src/stream.ts +505 -16
  64. package/src/types.ts +13 -0
  65. package/src/usage/ollama.ts +41 -0
  66. package/src/usage/openai-codex-base-url.ts +15 -0
  67. package/src/usage/openai-codex-reset.ts +1 -1
  68. package/src/usage/openai-codex.ts +30 -15
  69. package/src/usage.ts +26 -0
  70. package/src/utils/thinking-loop.ts +183 -18
  71. package/dist/types/utils/json-parse.d.ts +0 -48
  72. package/src/utils/json-parse.ts +0 -558
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.2.0] - 2026-06-27
6
+
7
+ ### Breaking Changes
8
+
9
+ - Removed the `@oh-my-pi/pi-ai/utils/json-parse` module. The JSON repair and parsing helpers (`repairJson`, `parseJsonWithRepair`, `parseStreamingJson`, `parseStreamingJsonThrottled`) have been moved to `@oh-my-pi/pi-utils` to be shared across utilities.
10
+
11
+ ### Added
12
+
13
+ - Added the GitLab Duo Agent provider (`gitlab-duo-agent`) and built-in implementation, renaming the existing AI Gateway proxy provider to "GitLab Duo Non-Agentic" (`gitlab-duo`).
14
+ - Added GitLab Duo Workflow provider support, featuring OAuth login via the official VS Code OAuth application, automatic project discovery, and automatic session-time namespace Duo settings enablement.
15
+ - Added runaway detection for Gemini models to interrupt streams stuck in excessive planning steps.
16
+ - Added a per-provider in-flight request limiter for LLM streams, shared across local OMP processes and configurable via `maxInFlightRequests`.
17
+ - Added a `credits` field to `UsageResetCredits` to display when banked rate-limit resets expire, with support for OpenAI Codex usage details.
18
+
19
+ ### Changed
20
+
21
+ - Optimized GitLab Duo Agent and Workflow providers to use an inline custom "ambient" flow with MCP-only agent privileges, registering MCP tools under their bare names.
22
+ - Improved GitLab Duo Agent context management and auto-compaction by lowering the soft overflow threshold to 1 MB and stripping redundant bytes (such as tool-call UUIDs and escaped JSON) from the goal transcript.
23
+ - Enhanced GitLab Duo Agent prompt engineering to render replayed tool calls as past-tense records, reducing model confusion and preventing the model from mimicking historical markers.
24
+ - Added caching for discovered GitLab Duo Agent root namespaces per account to avoid redundant discovery requests.
25
+
26
+ ### Fixed
27
+
28
+ - Fixed various GitLab Duo Agent and Workflow stability issues, including infinite tool-call loops, connection hangs on half-open WebSockets, and unhandled step-limit or generic server-side failures.
29
+ - Improved GitLab Duo Workflow routing, namespace resolution, and project-path handling, ensuring correct numeric ID resolution and support for self-managed GitLab relative install base paths.
30
+ - Fixed GitLab Duo Workflow checkpoint streaming to correctly map reasoning entries to thinking blocks, preserve tool boundaries, and accurately report token usage.
31
+ - Fixed `AuthStorage.login` to only synthesize manual-code paste prompts for paste-code providers, preventing terminal-blocking races on loopback OAuth flows.
32
+ - Fixed llama.cpp compatibility by downgrading named forced `tool_choice` objects to the string `"required"` in the chat-completions encoder.
33
+ - Fixed `omp usage` omitting Ollama and Ollama Cloud accounts by registering placeholder usage providers.
34
+ - Fixed Gemini reasoning-runaway detection to expose a dedicated thought-summary header guard to interrupt streams stuck in planning loops.
35
+
36
+ ### Removed
37
+
38
+ - Removed legacy GitLab Duo Workflow `chat` and `software_development` flow paths and the non-MCP action bridge in favor of the inline custom `ambient` flow.
39
+
40
+ ## [16.1.23] - 2026-06-26
41
+
42
+ ### Added
43
+
44
+ - Added a third streaming thinking-loop detection heuristic to catch "progress-lexicon stalls" where models endlessly reshuffle motivational filler without introducing new vocabulary or concrete technical references
45
+ - Added branded wordmark and logo animation to authentication flow
46
+ - Added a third streaming thinking-loop detection shape — a *progress-lexicon stall* — alongside verbatim tail repetition and near-duplicate (trigram) segments. It catches reasoning-summarizer loops that reshuffle the same motivational filler ("just doing it, pushing ahead, maintaining momentum") into fresh word order every paragraph: word-trigrams never cluster, but a run of substantial segments that recycle the recent vocabulary and introduce no *new* concrete reference (path / identifier / code-span) trips the guard. Summarizer title/heading lines (`**Bold Title**`, `## Heading`) are stripped before analysis so their ever-changing wording cannot mask the stall by inflating novelty. Calibrated against 537k real non-Gemini reasoning blocks (zero false positives at novelty floor 0.2 / run length 8; the real loop sustains runs of 10+).
47
+ - Added CoreWeave Serverless Inference provider login support via `COREWEAVE_API_KEY` and `WANDB_API_KEY` fallback.
48
+
49
+ ### Changed
50
+
51
+ - Redesigned the OAuth callback page (`oauth.html`) to match the oh-my-pi web brand language: OKLCH purple-tinted dark neutrals, magenta→iris→cyan brand gradient on the wordmark, frosted-glass card over an ascii grid backdrop, and a colored status halo around the success/error icon. All assets are inlined; the `__OAUTH_STATE__` injection contract and success/error JS logic are unchanged.
52
+
53
+ ### Fixed
54
+
55
+ - Fixed local llama.cpp (and any local OpenAI-compatible server rendering the Qwen3.6+ chat template) re-processing the full prompt every new user message even with `replayReasoningContent` enabled (#3541 follow-up to #3528). Sending `reasoning_content` alone wasn't enough: Qwen3's chat template strips `<think>...</think>` from any assistant turn whose index is `<= last_query_index`, so the moment a new user message (the user's next prompt, or the auto-learn capture-at-stop nudge) lands, every prior assistant turn becomes "older" and is re-rendered without the `<think>` block — diverging from the generation tokens still in the slot's KV cache. The chat-completions encoder now emits `preserve_thinking: true` for Qwen thinking dialects on local servers, route-split the same way the existing `enable_thinking` emission is: the `qwen` dialect rides the top-level field (llama.cpp's `--jinja` hook and Alibaba Cloud Model Studio's compatible-mode), the `qwen-chat-template` dialect (NVIDIA NIM, vLLM/SGLang's chat-template-kwargs path) rides only `chat_template_kwargs.preserve_thinking` because NIM's request schema is `additionalProperties: false` and rejects unknown top-level fields (#2299). The emission is hoisted above the `reasoning.enabled` gate so it fires for THREE cases the original gating missed: (1) runtime-discovered local Qwen models that ship with `reasoning: false` because the upstream `/v1/models` doesn't advertise the capability (same gotcha #3532 fixed for `replayReasoningContent`), (2) caller-disabled reasoning (`/think off`) — the kwarg is a history-rendering knob, not a per-turn thinking switch, and the slot still holds `<think>` tokens from earlier turns, and (3) forced-tool-choice / DeepSeek-style auto-disable. Qwen3.6+ then renders `<think>...</think>` for every assistant turn regardless of position, and the next-turn render matches the cached generation tokens. ([#3541](https://github.com/can1357/oh-my-pi/issues/3541))
56
+
5
57
  ## [16.1.22] - 2026-06-26
6
58
 
7
59
  ### Fixed
@@ -331,6 +331,11 @@ export declare const usageResponseSchema: import("arktype/internal/variants/obje
331
331
  }[];
332
332
  resetCredits?: {
333
333
  availableCount: number;
334
+ credits?: {
335
+ grantedAt?: string | undefined;
336
+ expiresAt?: string | undefined;
337
+ status?: string | undefined;
338
+ }[] | undefined;
334
339
  } | undefined;
335
340
  notes?: string[] | undefined;
336
341
  metadata?: {
@@ -13,6 +13,7 @@ export * from "./providers/anthropic-client";
13
13
  export * from "./providers/azure-openai-responses";
14
14
  export type * from "./providers/cursor";
15
15
  export * from "./providers/gitlab-duo";
16
+ export * from "./providers/gitlab-duo-workflow";
16
17
  export type * from "./providers/google";
17
18
  export type * from "./providers/google-gemini-cli";
18
19
  export type * from "./providers/google-vertex";
@@ -34,6 +35,7 @@ export * from "./usage/github-copilot";
34
35
  export * from "./usage/google-antigravity";
35
36
  export * from "./usage/kimi";
36
37
  export * from "./usage/minimax-code";
38
+ export * from "./usage/ollama";
37
39
  export * from "./usage/openai-codex";
38
40
  export * from "./usage/openai-codex-reset";
39
41
  export * from "./usage/opencode-go";
@@ -103,6 +103,17 @@ export declare const userMessageSchema: import("arktype/internal/variants/object
103
103
  type: string;
104
104
  })[];
105
105
  }, {}>;
106
+ export declare const systemMessageSchema: import("arktype/internal/variants/object.ts").ObjectType<{
107
+ role: "system";
108
+ content: string | {
109
+ type: "text";
110
+ text: string;
111
+ cache_control?: {
112
+ type: "ephemeral";
113
+ ttl?: "1h" | "5m" | undefined;
114
+ } | undefined;
115
+ }[];
116
+ }, {}>;
106
117
  export declare const assistantMessageSchema: import("arktype/internal/variants/object.ts").ObjectType<{
107
118
  role: "assistant";
108
119
  content: string | ({
@@ -204,6 +215,16 @@ export declare const messageSchema: import("arktype/internal/variants/object.ts"
204
215
  } | {
205
216
  type: string;
206
217
  })[];
218
+ } | {
219
+ role: "system";
220
+ content: string | {
221
+ type: "text";
222
+ text: string;
223
+ cache_control?: {
224
+ type: "ephemeral";
225
+ ttl?: "1h" | "5m" | undefined;
226
+ } | undefined;
227
+ }[];
207
228
  } | {
208
229
  role: "assistant";
209
230
  content: string | ({
@@ -344,6 +365,16 @@ export declare const anthropicMessagesRequestSchema: import("arktype/internal/va
344
365
  } | {
345
366
  type: string;
346
367
  })[];
368
+ } | {
369
+ role: "system";
370
+ content: string | {
371
+ type: "text";
372
+ text: string;
373
+ cache_control?: {
374
+ type: "ephemeral";
375
+ ttl?: "1h" | "5m" | undefined;
376
+ } | undefined;
377
+ }[];
347
378
  } | {
348
379
  role: "assistant";
349
380
  content: string | ({
@@ -0,0 +1,254 @@
1
+ import { type GitLabDuoWorkflowNamespaceSelection } from "@oh-my-pi/pi-catalog/discovery/gitlab-duo-workflow";
2
+ import type { AssistantMessage, Context, FetchImpl, Model, ProviderSessionState, StreamFunction, StreamOptions, Tool, ToolChoice, ToolResultMessage } from "../types";
3
+ import { AssistantMessageEventStream } from "../utils/event-stream";
4
+ export declare const GITLAB_DUO_WORKFLOW_PROVIDER_ID = "gitlab-duo-agent";
5
+ export declare const GITLAB_DUO_WORKFLOW_API = "gitlab-duo-agent";
6
+ export declare const GITLAB_DUO_WORKFLOW_DEFINITION = "ambient";
7
+ export type GitLabDuoWorkflowDefinition = "ambient" | (string & {});
8
+ export declare const GITLAB_DUO_WORKFLOW_CLIENT_CAPABILITIES: readonly ["incremental_streaming", "read_file_chunked", "shell_command", "command_timeout", "tool_call_approval"];
9
+ export interface GitLabMcpToolArgs {
10
+ name?: string;
11
+ tool_name?: string;
12
+ toolName?: string;
13
+ providerIdentifier?: string;
14
+ provider_identifier?: string;
15
+ toolCallId?: string;
16
+ tool_call_id?: string;
17
+ args?: Record<string, unknown> | string;
18
+ arguments?: Record<string, unknown> | string;
19
+ }
20
+ export interface GitLabPlainTextResponse {
21
+ response?: string;
22
+ error?: string;
23
+ }
24
+ export type PlainTextResponse = GitLabPlainTextResponse;
25
+ export interface GitLabDuoWorkflowOptions extends StreamOptions {
26
+ rootNamespaceId?: string;
27
+ namespaceId?: string;
28
+ projectId?: string;
29
+ projectPath?: string;
30
+ workflowDefinition?: GitLabDuoWorkflowDefinition;
31
+ workflowId?: string;
32
+ workflowToken?: string;
33
+ cwd?: string;
34
+ webSocketFactory?: GitLabDuoWorkflowWebSocketFactory;
35
+ /** Idle WebSocket deadline (ms) before aborting and resuming; defaults to {@link GITLAB_DUO_WORKFLOW_IDLE_TIMEOUT_MS}. */
36
+ idleTimeoutMs?: number;
37
+ /**
38
+ * Tool-choice override forwarded from the stream layer. Only `"none"` is
39
+ * acted on: a side-request (e.g. handoff) keeps tool definitions in the cache
40
+ * prefix but disables tool use, so the provider must not advertise them to Duo.
41
+ */
42
+ toolChoice?: ToolChoice;
43
+ }
44
+ export interface GitLabDuoWorkflowWebSocketLike {
45
+ readyState?: number;
46
+ binaryType?: string;
47
+ onopen: ((event: Event) => void) | null;
48
+ onmessage: ((event: MessageEvent) => void) | null;
49
+ onerror: ((event: Event) => void) | null;
50
+ onclose: ((event: CloseEvent) => void) | null;
51
+ send(data: string): void;
52
+ close(code?: number, reason?: string): void;
53
+ }
54
+ export interface GitLabDuoWorkflowWebSocketFactoryOptions {
55
+ headers: Record<string, string>;
56
+ protocols?: string[];
57
+ }
58
+ export type GitLabDuoWorkflowWebSocketFactory = (url: string, options: GitLabDuoWorkflowWebSocketFactoryOptions) => GitLabDuoWorkflowWebSocketLike;
59
+ export interface GitLabDirectAccessResponse {
60
+ token?: string;
61
+ access_token?: string;
62
+ jwt?: string;
63
+ workflow_token?: string;
64
+ duo_workflow_access_token?: string;
65
+ duo_workflow_service?: {
66
+ token?: string;
67
+ base_url?: string;
68
+ headers?: Record<string, string>;
69
+ };
70
+ gitlab_rails?: {
71
+ token?: string;
72
+ };
73
+ [key: string]: unknown;
74
+ }
75
+ interface GitLabDuoWorkflowCreateBodyOptions {
76
+ projectId?: string;
77
+ goal?: string;
78
+ workflowDefinition?: GitLabDuoWorkflowDefinition;
79
+ }
80
+ interface GitLabDuoWorkflowStartMetadataOptions {
81
+ projectId?: string;
82
+ projectPath?: string;
83
+ namespaceId?: string;
84
+ rootNamespaceId?: string;
85
+ workflowDefinition?: GitLabDuoWorkflowDefinition;
86
+ inlineFlow?: boolean;
87
+ }
88
+ export interface GitLabMcpToolDefinition {
89
+ name: string;
90
+ originalToolName: string;
91
+ serverName: string;
92
+ description: string;
93
+ inputSchema: string;
94
+ isApproved: boolean;
95
+ }
96
+ export interface GitLabDuoWorkflowAdditionalContextItem {
97
+ id: string;
98
+ category: "agent_user_environment" | "user_rule";
99
+ content: string;
100
+ metadata: {
101
+ title: string;
102
+ enabled: boolean;
103
+ subType: "snippet";
104
+ icon: string;
105
+ secondaryText: string;
106
+ subTypeLabel: string;
107
+ };
108
+ }
109
+ export interface GitLabDuoWorkflowStartRequest {
110
+ workflowID: string;
111
+ clientVersion: "1.0";
112
+ workflowDefinition: GitLabDuoWorkflowDefinition;
113
+ goal: string;
114
+ workflowMetadata: string;
115
+ additional_context: readonly GitLabDuoWorkflowAdditionalContextItem[];
116
+ approval?: {
117
+ approval?: Record<string, never>;
118
+ rejection?: {
119
+ message?: string;
120
+ };
121
+ };
122
+ clientCapabilities: readonly (typeof GITLAB_DUO_WORKFLOW_CLIENT_CAPABILITIES)[number][];
123
+ mcpTools: GitLabMcpToolDefinition[];
124
+ preapproved_tools: string[];
125
+ flowConfigSchemaVersion?: "v1";
126
+ flowConfigId?: string;
127
+ flowVersion?: string;
128
+ flowConfig?: GitLabDuoWorkflowInlineFlowConfig;
129
+ }
130
+ export interface GitLabDuoWorkflowInlineFlowComponent {
131
+ name: string;
132
+ type: "AgentComponent";
133
+ prompt_id: string;
134
+ toolset: string[];
135
+ inputs: {
136
+ from: string;
137
+ as: string;
138
+ }[];
139
+ ui_log_events: string[];
140
+ }
141
+ export interface GitLabDuoWorkflowInlineFlowPrompt {
142
+ name: string;
143
+ prompt_id: string;
144
+ unit_primitives: string[];
145
+ prompt_template: {
146
+ system: string;
147
+ user: string;
148
+ placeholder: string;
149
+ };
150
+ }
151
+ export interface GitLabDuoWorkflowInlineFlowConfig {
152
+ version: "v1";
153
+ environment: "ambient";
154
+ flow: {
155
+ entry_point: string;
156
+ };
157
+ components: GitLabDuoWorkflowInlineFlowComponent[];
158
+ routers: {
159
+ from: string;
160
+ to: string;
161
+ }[];
162
+ prompts: GitLabDuoWorkflowInlineFlowPrompt[];
163
+ }
164
+ export interface GitLabDuoWorkflowActionResponse {
165
+ actionResponse: {
166
+ requestID: string;
167
+ plainTextResponse?: GitLabPlainTextResponse;
168
+ };
169
+ }
170
+ interface GitLabDuoWorkflowActionDescriptor {
171
+ requestID: string;
172
+ name: string;
173
+ args: unknown;
174
+ }
175
+ export interface GitLabDuoWorkflowActiveSession {
176
+ workflowId: string;
177
+ startPayload: GitLabDuoWorkflowStartRequest;
178
+ ws: GitLabDuoWorkflowWebSocketLike;
179
+ stop?: () => void;
180
+ pendingActions?: GitLabDuoWorkflowActionDescriptor[];
181
+ checkpointAgentContentByKey?: Record<string, string>;
182
+ checkpointAgentContentSignatures?: Record<string, true>;
183
+ paused?: boolean;
184
+ pauseBuffer?: unknown[];
185
+ lastToolBoundaryContentLength?: number;
186
+ }
187
+ export interface GitLabDuoWorkflowProviderSessionState extends ProviderSessionState {
188
+ active?: GitLabDuoWorkflowActiveSession;
189
+ }
190
+ export interface GitLabDuoWorkflowStreamState {
191
+ stream: AssistantMessageEventStream;
192
+ output: AssistantMessage;
193
+ activeTextIndex?: number;
194
+ activeThinkingIndex?: number;
195
+ activeCheckpointMessageKey?: string;
196
+ started: boolean;
197
+ checkpointAgentContentByKey?: Record<string, string>;
198
+ checkpointAgentContentSignatures?: Record<string, true>;
199
+ pauseRequested?: boolean;
200
+ stepLimitRequested?: boolean;
201
+ retryableErrorRequested?: boolean;
202
+ lastCheckpointContentLength?: number;
203
+ stalledRequested?: boolean;
204
+ providerSessionState?: GitLabDuoWorkflowProviderSessionState;
205
+ lastApprovalStatus?: string;
206
+ goalOverflowMessage?: string;
207
+ }
208
+ type GitLabDuoWorkflowSocketResult = "closed" | "terminal" | "approval" | "action" | "pause" | "timeout" | "step_limit" | "retryable_error" | "stalled";
209
+ export interface GitLabAvailableModel {
210
+ name?: string | null;
211
+ ref?: string | null;
212
+ }
213
+ export interface GitLabAvailableModelsPayload {
214
+ pinnedModel?: GitLabAvailableModel | null;
215
+ selectedModel?: GitLabAvailableModel | null;
216
+ defaultModel?: GitLabAvailableModel | null;
217
+ selectableModels?: GitLabAvailableModel[] | null;
218
+ }
219
+ export declare const streamGitLabDuoWorkflow: StreamFunction<"gitlab-duo-agent">;
220
+ export declare function buildGitLabDuoWorkflowDirectAccessBody(rootNamespaceId: string, projectId?: string, workflowDefinition?: GitLabDuoWorkflowDefinition): Record<string, string>;
221
+ export declare function buildGitLabDuoWorkflowCreateBody(namespaceId?: string, options?: GitLabDuoWorkflowCreateBodyOptions): Record<string, string | boolean | string[] | number[]>;
222
+ export declare function buildGitLabDuoWorkflowStopBody(): Record<string, string>;
223
+ export declare function buildGitLabDuoWorkflowWebSocketUrl(baseUrl: string, options?: {
224
+ projectId?: string;
225
+ namespaceId?: string;
226
+ rootNamespaceId?: string;
227
+ selectedModelIdentifier?: string;
228
+ workflowDefinition?: GitLabDuoWorkflowDefinition;
229
+ serviceEndpoint?: boolean;
230
+ }): string;
231
+ export declare function buildGitLabDuoWorkflowWebSocketHeaders(options: {
232
+ token: string;
233
+ baseUrl?: string;
234
+ projectId?: string;
235
+ namespaceId?: string;
236
+ rootNamespaceId?: string;
237
+ extraHeaders?: Record<string, string>;
238
+ }): Record<string, string>;
239
+ export declare function buildGitLabDuoWorkflowStartRequest(workflowId: string, model: Model<"gitlab-duo-agent">, context: Context, tools?: Tool[] | undefined, availableModels?: GitLabAvailableModelsPayload | null, metadataOptions?: GitLabDuoWorkflowStartMetadataOptions): GitLabDuoWorkflowStartRequest;
240
+ export declare function buildGitLabDuoWorkflowInlineFlowConfig(systemPrompt: string): GitLabDuoWorkflowInlineFlowConfig;
241
+ export declare function buildGitLabDuoWorkflowClientAdditionalContext(): GitLabDuoWorkflowAdditionalContextItem[];
242
+ export declare function buildGitLabDuoWorkflowMcpTools(tools: Tool[] | undefined): GitLabMcpToolDefinition[];
243
+ export declare function selectGitLabDuoWorkflowModelRef(selectedModel: string, availableModels?: GitLabAvailableModelsPayload | null): string;
244
+ export declare function buildGitLabPlainTextFromToolResult(toolResult: ToolResultMessage): GitLabPlainTextResponse;
245
+ export declare function gitLabDuoWorkflowErrorText(error: unknown): string;
246
+ export declare function buildGitLabDuoWorkflowSettingsBody(): Record<string, unknown>;
247
+ export declare function runGitLabDuoWorkflowSocket(ws: GitLabDuoWorkflowWebSocketLike, startPayload: GitLabDuoWorkflowStartRequest, state: GitLabDuoWorkflowStreamState, options: GitLabDuoWorkflowOptions, resumeResponse?: GitLabDuoWorkflowActionResponse | readonly GitLabDuoWorkflowActionResponse[], replayMessages?: readonly unknown[]): Promise<GitLabDuoWorkflowSocketResult>;
248
+ export declare function buildGitLabDuoWorkflowApprovalStartRequest(startPayload: GitLabDuoWorkflowStartRequest): GitLabDuoWorkflowStartRequest;
249
+ export declare function describeGitLabDuoWorkflowSocketEvent(event: unknown): string;
250
+ export declare function traceGitLabDuoWorkflow(event: string, data?: Record<string, unknown>): void;
251
+ export declare function extractGitLabWorkflowToken(payload: GitLabDirectAccessResponse): string | undefined;
252
+ export declare function resolveGitLabDuoWorkflowNamespaceSelection(model: Model<"gitlab-duo-agent">, options: GitLabDuoWorkflowOptions, apiKey: string, baseUrl: string, fetchImpl: FetchImpl): Promise<GitLabDuoWorkflowNamespaceSelection>;
253
+ export declare function resolveGitLabDuoWorkflowRootNamespaceId(model: Model<"gitlab-duo-agent">, options: GitLabDuoWorkflowOptions, apiKey: string, baseUrl: string, fetchImpl: FetchImpl): Promise<string>;
254
+ export {};
@@ -194,8 +194,10 @@ export type OpenAICompletionsParams = Omit<ChatCompletionCreateParamsStreaming,
194
194
  keep?: "all";
195
195
  };
196
196
  enable_thinking?: boolean;
197
+ preserve_thinking?: boolean;
197
198
  chat_template_kwargs?: {
198
- enable_thinking: boolean;
199
+ enable_thinking?: boolean;
200
+ preserve_thinking?: boolean;
199
201
  };
200
202
  reasoning?: {
201
203
  effort?: string;
@@ -22,6 +22,7 @@ type ModelsEndpointValidation = {
22
22
  kind: "models-endpoint";
23
23
  provider: string;
24
24
  modelsUrl: string;
25
+ headers?: Record<string, string> | (() => Record<string, string> | undefined);
25
26
  };
26
27
  export type ApiKeyLoginConfig = {
27
28
  /** Display name used in error messages, e.g. "Cerebras", "NanoGPT". */
@@ -19,6 +19,7 @@ type ModelListValidationOptions = {
19
19
  provider: string;
20
20
  apiKey: string;
21
21
  modelsUrl: string;
22
+ headers?: Record<string, string> | (() => Record<string, string> | undefined);
22
23
  signal?: AbortSignal;
23
24
  fetch?: FetchImpl;
24
25
  };
@@ -0,0 +1,7 @@
1
+ import type { OAuthLoginCallbacks } from "./oauth/types";
2
+ export declare const loginCoreWeave: (options: import("./oauth").OAuthController) => Promise<string>;
3
+ export declare const coreWeaveProvider: {
4
+ readonly id: "coreweave";
5
+ readonly name: "CoreWeave Serverless Inference";
6
+ readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
7
+ };
@@ -0,0 +1,10 @@
1
+ import type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth/types";
2
+ export declare const gitLabDuoWorkflowProvider: {
3
+ readonly id: "gitlab-duo-agent";
4
+ readonly name: "GitLab Duo Agent";
5
+ readonly envKeys: "GITLAB_TOKEN";
6
+ readonly login: (cb: OAuthLoginCallbacks) => Promise<OAuthCredentials>;
7
+ readonly refreshToken: (credentials: OAuthCredentials) => Promise<OAuthCredentials>;
8
+ readonly callbackPort: 8080;
9
+ readonly pasteCodeFlow: true;
10
+ };
@@ -1,7 +1,7 @@
1
1
  import type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth/types";
2
2
  export declare const gitlabDuoProvider: {
3
3
  readonly id: "gitlab-duo";
4
- readonly name: "GitLab Duo";
4
+ readonly name: "GitLab Duo Non-Agentic";
5
5
  readonly login: (cb: OAuthLoginCallbacks) => Promise<OAuthCredentials>;
6
6
  readonly refreshToken: (credentials: OAuthCredentials) => Promise<OAuthCredentials>;
7
7
  readonly callbackPort: 8080;
@@ -0,0 +1,6 @@
1
+ import type { FetchImpl } from "../../types";
2
+ import type { OAuthCredentials, OAuthLoginCallbacks } from "./types";
3
+ export declare const GITLAB_DUO_WORKFLOW_OAUTH_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
4
+ export declare const GITLAB_DUO_WORKFLOW_OAUTH_REDIRECT_URI = "vscode://gitlab.gitlab-workflow/authentication";
5
+ export declare function loginGitLabDuoWorkflow(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
6
+ export declare function refreshGitLabDuoWorkflowToken(credentials: OAuthCredentials, fetchImpl?: FetchImpl): Promise<OAuthCredentials>;
@@ -37,6 +37,10 @@ declare const ALL: ({
37
37
  readonly id: "cloudflare-ai-gateway";
38
38
  readonly name: "Cloudflare AI Gateway";
39
39
  readonly login: (cb: import("./oauth").OAuthLoginCallbacks) => Promise<string>;
40
+ } | {
41
+ readonly id: "coreweave";
42
+ readonly name: "CoreWeave Serverless Inference";
43
+ readonly login: (cb: import("./oauth").OAuthLoginCallbacks) => Promise<string>;
40
44
  } | {
41
45
  readonly id: "cursor";
42
46
  readonly name: "Cursor (Claude, GPT, etc.)";
@@ -67,7 +71,15 @@ declare const ALL: ({
67
71
  readonly refreshToken: (credentials: import("./oauth").OAuthCredentials) => Promise<import("./oauth").OAuthCredentials>;
68
72
  } | {
69
73
  readonly id: "gitlab-duo";
70
- readonly name: "GitLab Duo";
74
+ readonly name: "GitLab Duo Non-Agentic";
75
+ readonly login: (cb: import("./oauth").OAuthLoginCallbacks) => Promise<import("./oauth").OAuthCredentials>;
76
+ readonly refreshToken: (credentials: import("./oauth").OAuthCredentials) => Promise<import("./oauth").OAuthCredentials>;
77
+ readonly callbackPort: 8080;
78
+ readonly pasteCodeFlow: true;
79
+ } | {
80
+ readonly id: "gitlab-duo-agent";
81
+ readonly name: "GitLab Duo Agent";
82
+ readonly envKeys: "GITLAB_TOKEN";
71
83
  readonly login: (cb: import("./oauth").OAuthLoginCallbacks) => Promise<import("./oauth").OAuthCredentials>;
72
84
  readonly refreshToken: (credentials: import("./oauth").OAuthCredentials) => Promise<import("./oauth").OAuthCredentials>;
73
85
  readonly callbackPort: 8080;
@@ -5,6 +5,14 @@ import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
5
5
  import type { GoogleVertexOptions } from "./providers/google-vertex";
6
6
  import type { Api, AssistantMessage, Context, Model, OptionsForApi, SimpleStreamOptions, ToolChoice } from "./types";
7
7
  import { AssistantMessageEventStream } from "./utils/event-stream";
8
+ export declare function configureProviderMaxInFlightRequests(limits: Record<string, number> | undefined): void;
9
+ export declare const __providerInFlightForTesting: {
10
+ setRoot(root: string | undefined): void;
11
+ providerDir(provider: string): string;
12
+ lockDir(provider: string): string;
13
+ captureStaleLockRelease(provider: string): Promise<(() => Promise<void>) | null>;
14
+ captureLockDirRelease(provider: string): Promise<(() => Promise<void>) | null>;
15
+ };
8
16
  /**
9
17
  * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
10
18
  *
@@ -12,6 +12,7 @@ import type { StopDetails } from "./providers/anthropic-wire";
12
12
  import type { AzureOpenAIResponsesOptions } from "./providers/azure-openai-responses";
13
13
  import type { CursorOptions } from "./providers/cursor";
14
14
  import type { DevinOptions } from "./providers/devin";
15
+ import type { GitLabDuoWorkflowOptions } from "./providers/gitlab-duo-workflow";
15
16
  import type { GoogleOptions } from "./providers/google";
16
17
  import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
17
18
  import type { GoogleVertexOptions } from "./providers/google-vertex";
@@ -47,6 +48,7 @@ export interface ApiOptionsMap {
47
48
  "google-vertex": GoogleVertexOptions;
48
49
  "ollama-chat": OllamaChatOptions;
49
50
  "cursor-agent": CursorOptions;
51
+ "gitlab-duo-agent": GitLabDuoWorkflowOptions;
50
52
  "devin-agent": DevinOptions;
51
53
  }
52
54
  export type OptionsForApi<TApi extends Api> = StreamOptions | (TApi extends keyof ApiOptionsMap ? ApiOptionsMap[TApi] : never);
@@ -201,6 +203,14 @@ export interface StreamOptions {
201
203
  * Providers can use this to persist transport/session state between turns.
202
204
  */
203
205
  providerSessionState?: Map<string, ProviderSessionState>;
206
+ /**
207
+ * Optional per-provider concurrent request cap for LLM stream calls. Keys are
208
+ * provider ids (`model.provider`); positive numeric values cap in-flight
209
+ * requests across local OMP processes that share the same config root. Omitted
210
+ * providers are unlimited. Non-chat provider APIs that bypass stream helpers
211
+ * are not covered.
212
+ */
213
+ maxInFlightRequests?: Record<string, number>;
204
214
  /**
205
215
  * Optional callback for inspecting or replacing provider payloads before sending.
206
216
  * Return undefined to keep the payload unchanged.
@@ -261,6 +271,8 @@ export interface StreamOptions {
261
271
  * channel) silently ignore the override.
262
272
  */
263
273
  fetch?: FetchImpl;
274
+ /** Current session working directory for providers that need workspace-scoped discovery. */
275
+ cwd?: string;
264
276
  /** Cursor exec/MCP tool handlers (cursor-agent only). */
265
277
  execHandlers?: CursorExecHandlers;
266
278
  }
@@ -0,0 +1,5 @@
1
+ import type { UsageProvider } from "../usage";
2
+ /** Registers Ollama accounts with usage views even though no quota endpoint is exposed. */
3
+ export declare const ollamaUsageProvider: UsageProvider;
4
+ /** Registers Ollama Cloud accounts with usage views until a quota endpoint is available. */
5
+ export declare const ollamaCloudUsageProvider: UsageProvider;
@@ -0,0 +1 @@
1
+ export declare function normalizeCodexBaseUrl(baseUrl?: string): string;
@@ -1,4 +1,3 @@
1
1
  import type { CredentialRankingStrategy, UsageProvider } from "../usage";
2
- export declare function normalizeCodexBaseUrl(baseUrl?: string): string;
3
2
  export declare const openaiCodexUsageProvider: UsageProvider;
4
3
  export declare const codexRankingStrategy: CredentialRankingStrategy;
@@ -50,6 +50,22 @@ export interface UsageLimit {
50
50
  status?: UsageStatus;
51
51
  notes?: string[];
52
52
  }
53
+ /**
54
+ * Per-credit detail for a saved/banked rate-limit reset.
55
+ *
56
+ * Populated when the provider's listing endpoint returns individual credit
57
+ * metadata (e.g. OpenAI Codex `wham/rate-limit-reset-credits`). Callers that
58
+ * only need the count can ignore this; display layers use `expiresAt` to show
59
+ * when banked resets expire ([#3339](https://github.com/can1357/oh-my-pi/issues/3339)).
60
+ */
61
+ export interface UsageResetCreditDetail {
62
+ /** ISO timestamp when the credit was granted. */
63
+ grantedAt?: string;
64
+ /** ISO timestamp when the credit expires and can no longer be redeemed. */
65
+ expiresAt?: string;
66
+ /** Backend status, e.g. `available`, `redeemed`. */
67
+ status?: string;
68
+ }
53
69
  /**
54
70
  * Saved/banked rate-limit resets an account can redeem on demand.
55
71
  *
@@ -60,6 +76,8 @@ export interface UsageLimit {
60
76
  export interface UsageResetCredits {
61
77
  /** Number of resets available to redeem right now. */
62
78
  availableCount: number;
79
+ /** Individual credit details (expiry dates, etc.) when the provider exposes them. */
80
+ credits?: UsageResetCreditDetail[];
63
81
  }
64
82
  /** Aggregated usage report for a provider. */
65
83
  export interface UsageReport {
@@ -188,8 +206,18 @@ export declare const usageLimitSchema: import("arktype/internal/variants/object.
188
206
  status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
189
207
  notes?: string[] | undefined;
190
208
  }, {}>;
209
+ export declare const usageResetCreditDetailSchema: import("arktype/internal/variants/object.ts").ObjectType<{
210
+ grantedAt?: string | undefined;
211
+ expiresAt?: string | undefined;
212
+ status?: string | undefined;
213
+ }, {}>;
191
214
  export declare const usageResetCreditsSchema: import("arktype/internal/variants/object.ts").ObjectType<{
192
215
  availableCount: number;
216
+ credits?: {
217
+ grantedAt?: string | undefined;
218
+ expiresAt?: string | undefined;
219
+ status?: string | undefined;
220
+ }[] | undefined;
193
221
  }, {}>;
194
222
  export declare const usageReportSchema: import("arktype/internal/variants/object.ts").ObjectType<{
195
223
  provider: string;
@@ -226,6 +254,11 @@ export declare const usageReportSchema: import("arktype/internal/variants/object
226
254
  }[];
227
255
  resetCredits?: {
228
256
  availableCount: number;
257
+ credits?: {
258
+ grantedAt?: string | undefined;
259
+ expiresAt?: string | undefined;
260
+ status?: string | undefined;
261
+ }[] | undefined;
229
262
  } | undefined;
230
263
  notes?: string[] | undefined;
231
264
  metadata?: {