@yaag/runtime 0.8.3 → 0.9.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.
- package/package.json +1 -1
- package/src/ask/ask-exchange-events.ts +10 -1
- package/src/ask/ask-exchange.ts +3 -0
- package/src/events.ts +14 -0
- package/src/model/model-fallback.ts +4 -1
- package/src/summary/summary-agent.ts +5 -0
- package/src/summary/summary-fallbacks.ts +2 -3
- package/src/summary/summary-model.ts +18 -0
- package/src/summary/summary.ts +7 -0
- package/src/transport/fake-transport.ts +4 -1
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ export interface AskEndOutcome {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Emits the Ask-scoped Lifecycle Events for one exchange, plus the Agent-scoped
|
|
19
|
-
* `model_fallback` this exchange's fallback loop reports.
|
|
19
|
+
* `model_fallback` and `agent_model` this exchange's fallback loop reports.
|
|
20
20
|
*/
|
|
21
21
|
export class AskEvents {
|
|
22
22
|
readonly #emit: EventSink;
|
|
@@ -66,6 +66,15 @@ export class AskEvents {
|
|
|
66
66
|
this.#emit({ type: "model_fallback", agent: this.#agent, ...fallback });
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The concrete model the Agent runs after a swap that landed (ADR-0041).
|
|
71
|
+
* Agent-scoped like `fallback`: the pattern side of the story stays in
|
|
72
|
+
* `model_fallback`, and this carries pi's own `provider/id`.
|
|
73
|
+
*/
|
|
74
|
+
model = (model: string): void => {
|
|
75
|
+
this.#emit({ type: "agent_model", agent: this.#agent, model });
|
|
76
|
+
};
|
|
77
|
+
|
|
69
78
|
/** A `normal` cause is the absent default, so ordinary settlements stay lean. */
|
|
70
79
|
end(outcome: AskEndOutcome): void {
|
|
71
80
|
const { durationMs, ok, maxFrameGapMs, cause = "normal" } = outcome;
|
package/src/ask/ask-exchange.ts
CHANGED
|
@@ -112,6 +112,9 @@ class AskExchange {
|
|
|
112
112
|
selection,
|
|
113
113
|
});
|
|
114
114
|
fallback.onSwapped(selection.model ?? swapped.model, swapped.model);
|
|
115
|
+
// Only a swap that landed reports a model: a refused `set_model` throws
|
|
116
|
+
// above and re-enters the loop, so the loop itself stays event-free.
|
|
117
|
+
this.#events.model(swapped.model);
|
|
115
118
|
},
|
|
116
119
|
});
|
|
117
120
|
}
|
package/src/events.ts
CHANGED
|
@@ -137,6 +137,20 @@ export type LifecycleEventBody =
|
|
|
137
137
|
/** The candidate resolution picked next. */
|
|
138
138
|
readonly resolvedModel: string;
|
|
139
139
|
}
|
|
140
|
+
| {
|
|
141
|
+
/**
|
|
142
|
+
* The concrete model an Agent runs from now on, reported when it changes
|
|
143
|
+
* after spawn. Today the only producer is a successful mid-Ask model swap
|
|
144
|
+
* (ADR-0038, ADR-0041): `model_fallback` names the pattern the resolver
|
|
145
|
+
* picked, this names the `provider/id` pi landed on, so `agent.model`
|
|
146
|
+
* stays concrete. Spawn needs none: `agent_spawn.model` is already
|
|
147
|
+
* concrete.
|
|
148
|
+
*/
|
|
149
|
+
readonly type: "agent_model";
|
|
150
|
+
readonly agent: string;
|
|
151
|
+
/** pi's concrete `provider/id` for the model the Agent runs now. */
|
|
152
|
+
readonly model: string;
|
|
153
|
+
}
|
|
140
154
|
| {
|
|
141
155
|
readonly type: "agent_usage";
|
|
142
156
|
readonly agent: string;
|
|
@@ -7,7 +7,10 @@ export interface ModelFallback {
|
|
|
7
7
|
readonly reason: ModelErrorReason;
|
|
8
8
|
/** 0-based index of the failed attempt in the Agent's shared history. */
|
|
9
9
|
readonly attempt: number;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* The candidate the resolver picked next. It is a yaag pattern, not a
|
|
12
|
+
* concrete `provider/id`, so it is never an Agent's model (ADR-0041).
|
|
13
|
+
*/
|
|
11
14
|
readonly resolvedModel: string;
|
|
12
15
|
}
|
|
13
16
|
|
|
@@ -12,6 +12,11 @@ export type AgentState = "idle" | "asking" | "exited";
|
|
|
12
12
|
|
|
13
13
|
/** Identity and accounting facts that apply in every observer Agent state. */
|
|
14
14
|
interface AgentInfoBase {
|
|
15
|
+
/**
|
|
16
|
+
* Always the concrete `provider/id` pi reports — from `agent_spawn` at spawn
|
|
17
|
+
* and from `agent_model` after every Model Fallback that landed (ADR-0041).
|
|
18
|
+
* A `resolvedModel` pattern never lands here.
|
|
19
|
+
*/
|
|
15
20
|
readonly model: string | null;
|
|
16
21
|
readonly cwd: string | null;
|
|
17
22
|
readonly branch: string | null;
|
|
@@ -24,9 +24,8 @@ type ModelFallbackEvent = Extract<LifecycleEventBody, { readonly type: "model_fa
|
|
|
24
24
|
* The Agent's `model` is left alone. `resolvedModel` is a yaag pattern, which
|
|
25
25
|
* can be partial, and the event reports it before the swap is applied, while
|
|
26
26
|
* `model` is pi's resolved `provider/id` for the model the Agent really runs.
|
|
27
|
-
* `agent_spawn`
|
|
28
|
-
*
|
|
29
|
-
* spawn-time id.
|
|
27
|
+
* Only `agent_spawn` and `agent_model` write that field: a mid-Ask swap that
|
|
28
|
+
* lands reports the concrete model in its own `agent_model` event (ADR-0041).
|
|
30
29
|
*/
|
|
31
30
|
export function applyModelFallback(
|
|
32
31
|
agent: AgentRecord,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LifecycleEventBody } from "../events.ts";
|
|
2
|
+
import type { AgentRecord } from "./summary-agent.ts";
|
|
3
|
+
|
|
4
|
+
type AgentModelEvent = Extract<LifecycleEventBody, { readonly type: "agent_model" }>;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Folds the concrete model an Agent runs now (ADR-0041).
|
|
8
|
+
*
|
|
9
|
+
* The event reports pi's `provider/id` after a swap landed, so it replaces
|
|
10
|
+
* `model` and nothing else: a model change is not a lifecycle state change, and
|
|
11
|
+
* `state`, `askIndex`, `activity`, `stateChangedAt` and the bounded fallback
|
|
12
|
+
* table stay as they are. An exited Agent is skipped, because its model is
|
|
13
|
+
* frozen together with its final accounting.
|
|
14
|
+
*/
|
|
15
|
+
export function applyAgentModel(agent: AgentRecord, event: AgentModelEvent): AgentRecord {
|
|
16
|
+
if (agent.state === "exited") return agent;
|
|
17
|
+
return { ...agent, model: event.model };
|
|
18
|
+
}
|
package/src/summary/summary.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
totalsFromAgents,
|
|
14
14
|
} from "./summary-agent.ts";
|
|
15
15
|
import { applyModelFallback } from "./summary-fallbacks.ts";
|
|
16
|
+
import { applyAgentModel } from "./summary-model.ts";
|
|
16
17
|
import { applyNodeUpdate } from "./summary-nodes.ts";
|
|
17
18
|
|
|
18
19
|
export type { NodeState, NodeUsage, RunOutcome } from "../events.ts";
|
|
@@ -152,6 +153,12 @@ export function applyEvent(
|
|
|
152
153
|
event.agent,
|
|
153
154
|
applyModelFallback(summary.agents[event.agent] ?? placeholderAgent(), event, at),
|
|
154
155
|
);
|
|
156
|
+
case "agent_model":
|
|
157
|
+
return withAgent(
|
|
158
|
+
summary,
|
|
159
|
+
event.agent,
|
|
160
|
+
applyAgentModel(summary.agents[event.agent] ?? placeholderAgent(), event),
|
|
161
|
+
);
|
|
155
162
|
case "agent_usage":
|
|
156
163
|
return withAgent(summary, event.agent, setUsage(summary.agents[event.agent], event, at));
|
|
157
164
|
case "ask_end":
|
|
@@ -54,6 +54,8 @@ export interface FakeTransportOptions extends FakePromptScript {
|
|
|
54
54
|
readonly schemaCommandError?: string;
|
|
55
55
|
/** The snapshot answered to `get_available_models`; defaults to this fake's own model. */
|
|
56
56
|
readonly models?: readonly AvailableModel[];
|
|
57
|
+
/** The model this fake reports before any swap; defaults to a placeholder id. */
|
|
58
|
+
readonly model?: string;
|
|
57
59
|
/** Makes a `set_model` command fail, as pi does for a pair it does not know. */
|
|
58
60
|
readonly setModelError?: string;
|
|
59
61
|
/** Makes a `set_thinking_level` command fail. */
|
|
@@ -75,7 +77,7 @@ export interface FakeTransportOptions extends FakePromptScript {
|
|
|
75
77
|
* It never spawns or closes a real Agent process.
|
|
76
78
|
*/
|
|
77
79
|
export class FakeTransport implements AgentTransport {
|
|
78
|
-
#model
|
|
80
|
+
#model: string;
|
|
79
81
|
|
|
80
82
|
/** The model this fake currently reports, which a `set_model` swap updates. */
|
|
81
83
|
get model(): string {
|
|
@@ -101,6 +103,7 @@ export class FakeTransport implements AgentTransport {
|
|
|
101
103
|
|
|
102
104
|
constructor(options: FakeTransportOptions = {}) {
|
|
103
105
|
this.#options = options;
|
|
106
|
+
this.#model = options.model ?? "test/model";
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
send(frame: Frame): void {
|