@punica/editor 1.22.8 → 1.23.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@punica/editor",
3
- "version": "1.22.8",
3
+ "version": "1.23.0",
4
4
  "description": "Punica Editor",
5
5
  "private": false,
6
6
  "type": "module",
@@ -192,6 +192,71 @@ declare module 'punica' {
192
192
  compactionApplied: boolean;
193
193
  }
194
194
 
195
+ /**
196
+ * The `ai.agent*` event family — a run as it happens.
197
+ *
198
+ * Every loop in the fleet publishes these, and a consumer reads a run
199
+ * without knowing which loop produced it. The contract, including the
200
+ * three obligations that are NOT payload shape (one trace per run, the
201
+ * loop naming itself in `origin.id`, and the MCP scope being declared),
202
+ * is `docs/agent-loops.md`.
203
+ *
204
+ * Correlation is on the envelope, not in the payload: `traceId` is the
205
+ * run — the same field the run's audited calls carry, so one query
206
+ * returns both halves — and `ai.agentStep` additionally carries
207
+ * `spanId`, the turn's own span, which is the parent of every gateway
208
+ * call that turn made.
209
+ *
210
+ * Declared here because they were a convention inside one file until
211
+ * 1.23.0: the names existed only in `kernel/ai/agentLoop.ts`, so a
212
+ * second loop had nothing to conform to and a consumer nothing to read
213
+ * against.
214
+ */
215
+ export interface AgentStartedEvent {
216
+ runId: string;
217
+ query: string;
218
+ /** The conversation this run continues, when it continues one. */
219
+ sessionId?: string;
220
+ }
221
+
222
+ /** One completed turn. Published after the model answers, per iteration. */
223
+ export interface AgentStepEvent {
224
+ runId: string;
225
+ turn: AgentTurn;
226
+ }
227
+
228
+ /** A tool the model asked for, published before it is dispatched. */
229
+ export interface AgentToolCallEvent {
230
+ runId: string;
231
+ toolCall: {
232
+ id: string;
233
+ name: string;
234
+ arguments: Record<string, unknown>;
235
+ };
236
+ status: 'running';
237
+ }
238
+
239
+ /**
240
+ * How that tool call settled. `status` repeats the call's own, so a
241
+ * consumer that missed the request event still learns the outcome —
242
+ * `blocked` among them, which is a refusal and not an error.
243
+ */
244
+ export interface AgentToolResultEvent {
245
+ runId: string;
246
+ toolCall: AgentToolCall;
247
+ status: AgentToolCall['status'];
248
+ }
249
+
250
+ /** Exactly one per run, whatever the outcome. */
251
+ export interface AgentFinishedEvent {
252
+ runId: string;
253
+ finishReason: AgentFinishReason;
254
+ finalText?: string;
255
+ usage?: AgentRunUsage;
256
+ /** The failure's own text, when `finishReason === 'error'`. */
257
+ error?: string;
258
+ }
259
+
195
260
  /**
196
261
  * Why an agent run stopped.
197
262
  * - `final` — the model produced a tool-call-free answer.
@@ -230,6 +295,22 @@ declare module 'punica' {
230
295
  * unpersisted, exactly as before sessions existed.
231
296
  */
232
297
  sessionId?: string;
298
+ /**
299
+ * The trace this run belongs to, when it is part of something bigger.
300
+ *
301
+ * A caller that is itself a governed call — an `ivy.agent.turn` node
302
+ * inside a graph run is the case this exists for — passes its own
303
+ * `ctx.trace` here, and the loop's model call and every tool the model
304
+ * then asks for are audited under that trace, one level below the
305
+ * caller's span. Omitted ⇒ the run is its own trace, exactly as
306
+ * before.
307
+ *
308
+ * Without it a turn minted a fresh trace, so the graph run and the
309
+ * work the model did inside it landed in the audit trail as two
310
+ * unrelated traces and neither an evidence package nor the run monitor
311
+ * could join them. Contract: `docs/agent-loops.md`.
312
+ */
313
+ trace?: { traceId: string; parentSpanId?: string };
233
314
  /**
234
315
  * Optional capability catalog filter (mirrors
235
316
  * `capability.schemaExport`'s filter shape). When omitted, the
@@ -293,10 +293,21 @@ declare module 'punica' {
293
293
  * own session/trace id. When `input.options.stream` is set, the
294
294
  * streaming `llm.chunk` deltas are published under this id so the
295
295
  * caller can correlate live tokens with the originating turn.
296
+ *
297
+ * `opts.trace` is the audit trail's side of the same idea and is not
298
+ * interchangeable with it: this call dispatches `llm.chat` back
299
+ * through the gateway, and without a trace to continue that inner
300
+ * call minted its own — so the model call an agent turn made was
301
+ * recorded outside the run that asked for it. Pass the caller's
302
+ * trace, and its own `invocationId` as `parentSpanId`, to get a
303
+ * parent/child pair instead.
296
304
  */
297
305
  invoke(
298
306
  input: CapabilityInput,
299
- opts?: { correlationId?: string }
307
+ opts?: {
308
+ correlationId?: string;
309
+ trace?: { traceId: string; parentSpanId?: string };
310
+ }
300
311
  ): Promise<CapabilityResult>;
301
312
 
302
313
  /**
@@ -277,6 +277,71 @@ declare module 'punica' {
277
277
  bytes: Uint8Array,
278
278
  signature: PackageSignature
279
279
  ) => Promise<boolean>;
280
+
281
+ /**
282
+ * Install the host's span exporter for the capability pipeline. The
283
+ * gateway produces an OTel-shaped `CapabilitySpan` for **every** call
284
+ * (`traceId` / `spanId` / `parentSpanId` / duration / status /
285
+ * attributes) and hands it here; the substrate ships no vendor SDK, so
286
+ * without this the spans go to a no-op.
287
+ *
288
+ * Keep `recordSpan` non-blocking — queue and flush. It is called
289
+ * synchronously on the success and failure path of every capability
290
+ * invocation, so a slow exporter slows the whole product down.
291
+ *
292
+ * On the facade since 1.23.0. Before that it was a named module export
293
+ * the package entry did not re-export, which put it in the same class as
294
+ * `setLlmPricingTable`: documented, exported, and absent from the
295
+ * published bundle, so no host could reach it.
296
+ */
297
+ setCapabilityTelemetryExporter: (
298
+ exporter: CapabilityTelemetryExporter | undefined
299
+ ) => void;
300
+
301
+ /** The installed capability exporter — never undefined; a no-op by default. */
302
+ getCapabilityTelemetryExporter: () => CapabilityTelemetryExporter;
303
+
304
+ /**
305
+ * Install the host's span exporter for kernel events. Same contract as
306
+ * the capability exporter and the same history; `publishEvent` calls
307
+ * `exportSpan` for every event, so the two together are what an OTel
308
+ * consumer needs to read a run from outside.
309
+ */
310
+ setEventTelemetryExporter: (
311
+ exporter: kernel.EventTelemetryExporter | undefined
312
+ ) => void;
313
+
314
+ /** The installed event exporter — never undefined; a no-op by default. */
315
+ getEventTelemetryExporter: () => kernel.EventTelemetryExporter;
316
+ }
317
+
318
+ /**
319
+ * One completed capability call, in the OpenTelemetry span shape so a host
320
+ * adapter is a field rename at most. `spanId` is the call's
321
+ * `invocationId`, which is also what the audit record carries, so the
322
+ * exported span and the durable record describe the same node of the same
323
+ * tree.
324
+ */
325
+ export interface CapabilitySpan {
326
+ invocationId: string;
327
+ capability: string;
328
+ traceId: string;
329
+ spanId: string;
330
+ parentSpanId?: string;
331
+ startTimeMs: number;
332
+ durationMs: number;
333
+ status: 'success' | 'error';
334
+ errorCode?: string;
335
+ errorMessage?: string;
336
+ attributes: Record<string, string>;
337
+ }
338
+
339
+ /**
340
+ * Host contract for receiving capability spans. Implementations MUST be
341
+ * non-blocking; the substrate calls this from the middleware's hot path.
342
+ */
343
+ export interface CapabilityTelemetryExporter {
344
+ recordSpan(span: CapabilitySpan): void;
280
345
  }
281
346
 
282
347
  /**
@@ -336,7 +401,6 @@ declare module 'punica' {
336
401
  Pick<PackageSignature, 'alg' | 'publicKeyJwk' | 'keyId'>
337
402
  >;
338
403
  }
339
-
340
404
  }
341
405
 
342
406
  export const runtime: runtime.RuntimeApi;
@@ -25,10 +25,18 @@ declare module 'punica' {
25
25
 
26
26
  /**
27
27
  * Origin of the capability invocation.
28
+ *
29
+ * `capability` is one capability calling another: an extension handler
30
+ * that delegates part of its work through the gateway, or a core provider
31
+ * dispatching an inner call. It was missing from the set until 1.23.0, so
32
+ * such a caller had to describe itself as something it was not —
33
+ * `ivy-node.generate` and `ivy-mcp.generate` inherited the CALLER's origin
34
+ * instead, which was the closest true statement available. Inheriting the
35
+ * caller's `trace` stays right; inheriting its origin does not.
28
36
  */
29
37
  export interface InvocationOrigin {
30
38
  /** Kind of origin */
31
- kind: 'command' | 'workflow' | 'ai';
39
+ kind: 'command' | 'workflow' | 'ai' | 'capability';
32
40
  /** Unique identifier for the origin */
33
41
  id: string;
34
42
  /** Extension name (if applicable) */
@@ -61,6 +69,21 @@ declare module 'punica' {
61
69
  export interface InvocationContext {
62
70
  /** Session identifier */
63
71
  sessionId: string;
72
+ /**
73
+ * This call's own id, and the span id its audit record carries.
74
+ *
75
+ * **Set by the gateway**, not by the caller: anything a caller puts
76
+ * here is replaced, because a span id somebody else chose is a claim
77
+ * about the record rather than a fact of it. Present on the context a
78
+ * provider or an extension handler receives, absent on the one a caller
79
+ * builds — which is why it is optional.
80
+ *
81
+ * What it is for: a handler that re-enters the gateway passes it as
82
+ * `trace.parentSpanId` on the inner call, so the two calls read back as
83
+ * parent and child instead of as siblings. Contract:
84
+ * `docs/agent-loops.md`.
85
+ */
86
+ invocationId?: string;
64
87
  /**
65
88
  * Persistent AI conversation this call belongs to
66
89
  * (`kernel.AI.sessions` id). Distinct from `sessionId`, which is