@oh-my-pi/pi-agent-core 16.0.4 → 16.0.6

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/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.0.6] - 2026-06-18
6
+
7
+ ### Added
8
+
9
+ - Added `transformAssistantMessage` hook to `AgentOptions` and `Agent` to allow mutating the finalized assistant message before UI emission, context appending, or tool dispatch
10
+
11
+ ## [16.0.5] - 2026-06-17
12
+
13
+ ### Breaking Changes
14
+
15
+ - Changed `AgentOptions.getApiKey` and `AgentLoopConfig.getApiKey` to receive the active `Model` and return an API key or `ApiKeyResolver`, so credential routing stays model-scoped and retry context is no longer exposed through the agent-core API
16
+
17
+ ### Added
18
+
19
+ - Added agent-loop deadline support for graceful wall-clock session stops.
20
+
21
+ ### Changed
22
+
23
+ - Changed Gemini repetition-loop detection to live in the pi-ai stream layer instead of the agent loop. The agent no longer runs its own Gemini-gated verbatim repetition check (`detectRepetition`/`truncateRepetition`); loops now surface as a retryable transient stream error that the standard auto-retry path discards and re-samples, rather than a committed contentful error message.
24
+
25
+ ### Fixed
26
+
27
+ - Fixed `PI_DIALECT=minimax` being ignored by the owned tool-calling env selector. ([#2759](https://github.com/can1357/oh-my-pi/issues/2759))
28
+
5
29
  ## [16.0.1] - 2026-06-15
6
30
 
7
31
  ### Fixed
package/README.md CHANGED
@@ -151,8 +151,8 @@ const agent = new Agent({
151
151
  // Custom stream function (for proxy backends)
152
152
  streamFn: streamProxy,
153
153
 
154
- // Dynamic API key resolution (for expiring OAuth tokens)
155
- getApiKey: async (provider) => refreshToken(),
154
+ // Dynamic model-scoped API key resolution (for expiring OAuth tokens)
155
+ getApiKey: async (model) => tokenForModel(model),
156
156
 
157
157
  // Tool execution context (late-bound UI/session access)
158
158
  getToolContext: () => ({ /* app-defined */ }),
@@ -1,4 +1,4 @@
1
- import { type ApiKeyResolveContext, type AssistantMessage, type AssistantMessageEvent, type Context, type CursorExecHandlers, type CursorToolResultHandler, type Effort, type ImageContent, type Message, type Model, type ProviderSessionState, type ServiceTier, type SimpleStreamOptions, type ThinkingBudgets, type ToolChoice } from "@oh-my-pi/pi-ai";
1
+ import { type ApiKey, type AssistantMessage, type AssistantMessageEvent, type Context, type CursorExecHandlers, type CursorToolResultHandler, type Effort, type ImageContent, type Message, type Model, type ProviderSessionState, type ServiceTier, type SimpleStreamOptions, type ThinkingBudgets, type ToolChoice } from "@oh-my-pi/pi-ai";
2
2
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
3
3
  import type { HarmonyAuditEvent } from "@oh-my-pi/pi-ai/utils/harmony-leak";
4
4
  import type { AppendOnlyContextManager } from "./append-only-context";
@@ -47,6 +47,8 @@ export interface AgentOptions {
47
47
  * Custom stream function (for proxy backends, etc.). Default uses streamSimple.
48
48
  */
49
49
  streamFn?: StreamFn;
50
+ /** Absolute wall-clock deadline in Unix epoch milliseconds. */
51
+ deadline?: number;
50
52
  /**
51
53
  * Optional session identifier forwarded to LLM providers.
52
54
  * Used by providers that support session-based caching (e.g., OpenAI Codex).
@@ -62,10 +64,10 @@ export interface AgentOptions {
62
64
  */
63
65
  providerSessionState?: Map<string, ProviderSessionState>;
64
66
  /**
65
- * Resolves an API key dynamically for each LLM call.
66
- * Useful for expiring tokens (e.g., GitHub Copilot OAuth).
67
+ * Resolves an API key or resolver dynamically for each LLM call.
68
+ * Useful for expiring tokens and model-scoped credential routing.
67
69
  */
68
- getApiKey?: (provider: string, ctx?: ApiKeyResolveContext) => Promise<string | undefined> | string | undefined;
70
+ getApiKey?: (model: Model) => Promise<ApiKey | undefined> | ApiKey | undefined;
69
71
  /**
70
72
  * Inspect or replace provider payloads before they are sent.
71
73
  */
@@ -156,6 +158,12 @@ export interface AgentOptions {
156
158
  * message are emitted. See {@link AgentLoopConfig.afterToolCall} for full semantics.
157
159
  */
158
160
  afterToolCall?: AgentLoopConfig["afterToolCall"];
161
+ /**
162
+ * Called once an assistant message is finalized, before it reaches the
163
+ * context, the UI, or tool dispatch. May mutate the message in place (text +
164
+ * tool-call arguments). See {@link AgentLoopConfig.transformAssistantMessage}.
165
+ */
166
+ transformAssistantMessage?: AgentLoopConfig["transformAssistantMessage"];
159
167
  /**
160
168
  * Opt-in OpenTelemetry instrumentation. Passing `{}` enables the loop's
161
169
  * GenAI-semantic-convention spans using the global tracer provider. See
@@ -174,7 +182,7 @@ export interface AgentPromptOptions {
174
182
  export declare class Agent {
175
183
  #private;
176
184
  streamFn: StreamFn;
177
- getApiKey?: (provider: string, ctx?: ApiKeyResolveContext) => Promise<string | undefined> | string | undefined;
185
+ getApiKey?: (model: Model) => Promise<ApiKey | undefined> | ApiKey | undefined;
178
186
  /**
179
187
  * Hook invoked after tool arguments are validated and before execution.
180
188
  * Reassign at any time to swap the implementation (e.g. on extension reload).
@@ -185,6 +193,11 @@ export declare class Agent {
185
193
  * message emission. Reassign at any time to swap the implementation.
186
194
  */
187
195
  afterToolCall?: AgentLoopConfig["afterToolCall"];
196
+ /**
197
+ * Hook invoked once an assistant message is finalized, before context append,
198
+ * UI emission, and tool dispatch. Reassign at any time to swap the implementation.
199
+ */
200
+ transformAssistantMessage?: AgentLoopConfig["transformAssistantMessage"];
188
201
  constructor(opts?: AgentOptions);
189
202
  /**
190
203
  * Get the current session ID used for provider caching.
@@ -6,5 +6,6 @@ export * from "./proxy";
6
6
  export * from "./run-collector";
7
7
  export * from "./telemetry";
8
8
  export * from "./thinking";
9
+ export * from "./tokenizer";
9
10
  export * from "./types";
10
11
  export * from "./utils/yield";
@@ -0,0 +1 @@
1
+ export declare function countTokens(text: string | string[]): number;
@@ -1,4 +1,4 @@
1
- import type { ApiKeyResolveContext, AssistantMessage, AssistantMessageEvent, AssistantMessageEventStream, Context, Effort, ImageContent, Message, Model, SimpleStreamOptions, Static, streamSimple, TextContent, Tool, ToolChoice, ToolResultMessage, TSchema } from "@oh-my-pi/pi-ai";
1
+ import type { ApiKey, AssistantMessage, AssistantMessageEvent, AssistantMessageEventStream, Context, Effort, ImageContent, Message, Model, SimpleStreamOptions, Static, streamSimple, TextContent, Tool, ToolChoice, ToolResultMessage, TSchema } from "@oh-my-pi/pi-ai";
2
2
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
3
3
  import type { HarmonyAuditEvent } from "@oh-my-pi/pi-ai/utils/harmony-leak";
4
4
  import type { AppendOnlyContextManager } from "./append-only-context";
@@ -29,6 +29,8 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
29
29
  * Used by providers that support session-based caching (e.g., OpenAI Codex).
30
30
  */
31
31
  sessionId?: string;
32
+ /** Absolute wall-clock deadline in Unix epoch milliseconds. */
33
+ deadline?: number;
32
34
  /**
33
35
  * Optional resolver called per LLM request to produce request metadata.
34
36
  * When set, the agent loop evaluates it **after** `getApiKey` resolves the
@@ -87,12 +89,12 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
87
89
  */
88
90
  transformProviderContext?: (context: Context, model: Model) => Context;
89
91
  /**
90
- * Resolves an API key dynamically for each LLM call.
92
+ * Resolves the API key or resolver for the current model before each LLM call.
91
93
  *
92
- * Useful for short-lived OAuth tokens (e.g., GitHub Copilot) that may expire
93
- * during long-running tool execution phases.
94
+ * Returning an ApiKeyResolver lets the stream retry policy refresh or rotate
95
+ * the model-scoped credential after auth/usage-limit errors.
94
96
  */
95
- getApiKey?: (provider: string, ctx?: ApiKeyResolveContext) => Promise<string | undefined> | string | undefined;
97
+ getApiKey?: (model: Model) => Promise<ApiKey | undefined> | ApiKey | undefined;
96
98
  /**
97
99
  * Returns steering messages to inject into the conversation mid-run.
98
100
  *
@@ -243,6 +245,19 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
243
245
  * backlog so advice produced during the wait is injected as an aside).
244
246
  */
245
247
  onTurnEnd?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<void> | void;
248
+ /**
249
+ * Called once an assistant message is finalized from the model stream, before
250
+ * it is appended to the context, emitted as `message_end`, or its tool calls
251
+ * are validated and dispatched. The hook may mutate the message in place —
252
+ * both its text content and its tool-call arguments — and those edits are seen
253
+ * by the transcript, the UI, and tool execution alike (single source of truth).
254
+ *
255
+ * Used for inline macro expansion: rewriting `@[[runtime.name(args)]]` tokens
256
+ * to host-computed values before anything downstream consumes the message.
257
+ * Runs at most once per assistant message; must not throw (a throw would abort
258
+ * the turn).
259
+ */
260
+ transformAssistantMessage?: (message: AssistantMessage, signal?: AbortSignal) => Promise<void> | void;
246
261
  /**
247
262
  * Called after a tool finishes executing, before `tool_execution_end` and the
248
263
  * tool-result message are emitted.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-agent-core",
4
- "version": "16.0.4",
4
+ "version": "16.0.6",
5
5
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -35,11 +35,11 @@
35
35
  "fmt": "biome format --write ."
36
36
  },
37
37
  "dependencies": {
38
- "@oh-my-pi/pi-ai": "16.0.4",
39
- "@oh-my-pi/pi-catalog": "16.0.4",
40
- "@oh-my-pi/pi-natives": "16.0.4",
41
- "@oh-my-pi/pi-utils": "16.0.4",
42
- "@oh-my-pi/snapcompact": "16.0.4",
38
+ "@oh-my-pi/pi-ai": "16.0.6",
39
+ "@oh-my-pi/pi-catalog": "16.0.6",
40
+ "@oh-my-pi/pi-natives": "16.0.6",
41
+ "@oh-my-pi/pi-utils": "16.0.6",
42
+ "@oh-my-pi/snapcompact": "16.0.6",
43
43
  "@opentelemetry/api": "^1.9.1"
44
44
  },
45
45
  "devDependencies": {