@archmax-ai/harness 2.1.0 → 2.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.
- package/README.md +11 -1
- package/dist/assembly/compose.d.ts +3 -0
- package/dist/assembly/compose.js +9 -1
- package/dist/assembly/compose.js.map +1 -1
- package/dist/assembly/index.js +10 -2
- package/dist/assembly/index.js.map +1 -1
- package/dist/assembly/plain.js +9 -2
- package/dist/assembly/plain.js.map +1 -1
- package/dist/assembly/telemetry-middleware.d.ts +11 -0
- package/dist/assembly/telemetry-middleware.js +65 -0
- package/dist/assembly/telemetry-middleware.js.map +1 -0
- package/dist/authoring-skill/archmax-harness/references/backend-integration.md +20 -0
- package/dist/core/events.d.ts +2 -0
- package/dist/core/events.js +4 -0
- package/dist/core/events.js.map +1 -1
- package/dist/core/telemetry.d.ts +213 -0
- package/dist/core/telemetry.js +705 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/sandbox/ptc-gateway.d.ts +7 -0
- package/dist/sandbox/ptc-gateway.js +37 -3
- package/dist/sandbox/ptc-gateway.js.map +1 -1
- package/dist/workflow/automated.d.ts +3 -0
- package/dist/workflow/automated.js +2 -0
- package/dist/workflow/automated.js.map +1 -1
- package/dist/workflow/control-tools.d.ts +5 -0
- package/dist/workflow/control-tools.js +5 -0
- package/dist/workflow/control-tools.js.map +1 -1
- package/dist/workflow/governance.d.ts +7 -1
- package/dist/workflow/governance.js +90 -20
- package/dist/workflow/governance.js.map +1 -1
- package/dist/workflow/grader-state.d.ts +5 -17
- package/dist/workflow/grader-state.js +85 -6
- package/dist/workflow/grader-state.js.map +1 -1
- package/dist/workflow/middleware.d.ts +3 -0
- package/dist/workflow/middleware.js +2 -0
- package/dist/workflow/middleware.js.map +1 -1
- package/dist/workflow/turn-runner.d.ts +12 -0
- package/dist/workflow/turn-runner.js +91 -16
- package/dist/workflow/turn-runner.js.map +1 -1
- package/package.json +8 -1
- package/skills/archmax-harness/references/backend-integration.md +20 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry for the runtime: one span per turn, per visit to a state, per
|
|
3
|
+
* model call and per tool call, and the GenAI client metrics for every model
|
|
4
|
+
* call — reported through `@opentelemetry/api` alone (a peer dependency), so a
|
|
5
|
+
* host sees them in its own trace once it registers an SDK, and nothing at all
|
|
6
|
+
* happens when it registers none.
|
|
7
|
+
*
|
|
8
|
+
* This module owns every span name, attribute name and recorded value, which
|
|
9
|
+
* is how the metadata-only rule holds: it takes slugs, model ids, counts and
|
|
10
|
+
* outcomes, never a message, an argument, a result or an error's message, and
|
|
11
|
+
* it records no exception.
|
|
12
|
+
*
|
|
13
|
+
* Turn, model-call and tool-call spans are made at their call sites and are
|
|
14
|
+
* active while the call runs, so whatever the call causes — the provider's HTTP
|
|
15
|
+
* request, a host tool's own spans, a sub-workflow's child turn — nests under
|
|
16
|
+
* it. A state visit is not one call: the sites that move a session report it on
|
|
17
|
+
* the event stream, which {@link Telemetry.observe} follows, and its children
|
|
18
|
+
* are parented to it explicitly ({@link Telemetry.parentFor}).
|
|
19
|
+
*/
|
|
20
|
+
import { type Context } from "@opentelemetry/api";
|
|
21
|
+
import { type WorkflowLifecycleEvent } from "./events.js";
|
|
22
|
+
import { type PricingTable } from "./usage.js";
|
|
23
|
+
/** The instrumentation scope every span and metric is reported under. */
|
|
24
|
+
export declare const TELEMETRY_SCOPE = "@archmax-ai/harness";
|
|
25
|
+
/** Every attribute the runtime records, by the name the backend reads. */
|
|
26
|
+
export declare const TELEMETRY_ATTRIBUTES: {
|
|
27
|
+
readonly operation: "gen_ai.operation.name";
|
|
28
|
+
readonly agentName: "gen_ai.agent.name";
|
|
29
|
+
readonly conversationId: "gen_ai.conversation.id";
|
|
30
|
+
readonly provider: "gen_ai.provider.name";
|
|
31
|
+
readonly requestModel: "gen_ai.request.model";
|
|
32
|
+
readonly responseModel: "gen_ai.response.model";
|
|
33
|
+
readonly finishReasons: "gen_ai.response.finish_reasons";
|
|
34
|
+
readonly inputTokens: "gen_ai.usage.input_tokens";
|
|
35
|
+
readonly outputTokens: "gen_ai.usage.output_tokens";
|
|
36
|
+
readonly cacheReadTokens: "gen_ai.usage.cache_read.input_tokens";
|
|
37
|
+
readonly cacheCreationTokens: "gen_ai.usage.cache_creation.input_tokens";
|
|
38
|
+
readonly cost: "gen_ai.usage.cost";
|
|
39
|
+
readonly toolName: "gen_ai.tool.name";
|
|
40
|
+
readonly toolCallId: "gen_ai.tool.call.id";
|
|
41
|
+
readonly toolType: "gen_ai.tool.type";
|
|
42
|
+
readonly tokenType: "gen_ai.token.type";
|
|
43
|
+
readonly errorType: "error.type";
|
|
44
|
+
readonly state: "archmax.state";
|
|
45
|
+
readonly stateType: "archmax.state.type";
|
|
46
|
+
readonly stateNext: "archmax.state.next";
|
|
47
|
+
readonly stateResumed: "archmax.state.resumed";
|
|
48
|
+
readonly stateParked: "archmax.state.parked";
|
|
49
|
+
readonly raiseCode: "archmax.raise.code";
|
|
50
|
+
readonly turnResume: "archmax.turn.resume";
|
|
51
|
+
readonly sessionStatus: "archmax.session.status";
|
|
52
|
+
readonly dispatchId: "archmax.dispatch.id";
|
|
53
|
+
readonly modelRole: "archmax.model.role";
|
|
54
|
+
readonly responseToolCalls: "archmax.response.tool_calls";
|
|
55
|
+
readonly toolOrigin: "archmax.tool.origin";
|
|
56
|
+
readonly toolOutcome: "archmax.tool.outcome";
|
|
57
|
+
readonly toolRule: "archmax.tool.rule";
|
|
58
|
+
};
|
|
59
|
+
/** The two GenAI client metrics, by name. */
|
|
60
|
+
export declare const TELEMETRY_METRICS: {
|
|
61
|
+
readonly operationDuration: "gen_ai.client.operation.duration";
|
|
62
|
+
readonly tokenUsage: "gen_ai.client.token.usage";
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* A tool's name as a span reports it: the name when it is a plain tool
|
|
66
|
+
* identifier, else `unknown` — a model can call a tool by any string at all.
|
|
67
|
+
*/
|
|
68
|
+
export declare function reportedToolName(name: string): string;
|
|
69
|
+
/** A raise's code when it is a short token, else nothing: the raiser chose it. */
|
|
70
|
+
export declare function reportedRaiseCode(code: unknown): string | undefined;
|
|
71
|
+
/** A model id when it reads as one, else nothing. */
|
|
72
|
+
export declare function reportedModelId(id: unknown): string | undefined;
|
|
73
|
+
/** A tool call's id as a span reports it, when it reads as an id. */
|
|
74
|
+
export declare function reportedCallId(id: unknown): string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* An error's `error.type`: the HTTP status it carries (`429`), else its class
|
|
77
|
+
* name (`AbortError`, from its `name` or its constructor's), else `Error`.
|
|
78
|
+
* Never its message, which can quote what the call was given, and never a
|
|
79
|
+
* `name` that is not shaped like a class name.
|
|
80
|
+
*/
|
|
81
|
+
export declare function errorTypeOf(err: unknown): string;
|
|
82
|
+
/** The `gen_ai.provider.name` of a chat model, from LangChain's own model type. */
|
|
83
|
+
export declare function providerOf(model: unknown): string | undefined;
|
|
84
|
+
/** What starts a turn's span. */
|
|
85
|
+
export interface TurnStart {
|
|
86
|
+
sessionId: string;
|
|
87
|
+
/** The workflow slug; absent for a plain agent. */
|
|
88
|
+
workflow?: string;
|
|
89
|
+
/** The turn resumes a park (a decision, a reply, a delivery). */
|
|
90
|
+
resume?: boolean;
|
|
91
|
+
/** A state's type, for the state spans of a governed turn. */
|
|
92
|
+
stateType?: (slug: string) => string | undefined;
|
|
93
|
+
}
|
|
94
|
+
/** How a turn settled, read from what it returned. */
|
|
95
|
+
export interface TurnSettled {
|
|
96
|
+
/** The session's status after the turn. */
|
|
97
|
+
status?: string;
|
|
98
|
+
/** The state the turn ended in. */
|
|
99
|
+
state?: string;
|
|
100
|
+
}
|
|
101
|
+
/** A turn in flight: the context its work runs in, and how it ends. */
|
|
102
|
+
export interface TurnHandle {
|
|
103
|
+
context: Context;
|
|
104
|
+
/** Whether a provider is recording it: what spares a no-op turn any extra work. */
|
|
105
|
+
recording: boolean;
|
|
106
|
+
end(settled?: TurnSettled): void;
|
|
107
|
+
fail(err: unknown): void;
|
|
108
|
+
}
|
|
109
|
+
/** A model call in flight. */
|
|
110
|
+
export interface ModelCallHandle {
|
|
111
|
+
/** The context the call runs in: its span active. */
|
|
112
|
+
context: Context;
|
|
113
|
+
/** The call answered: its usage, the model it named, its finish. Ends the span. */
|
|
114
|
+
settle(response: unknown): void;
|
|
115
|
+
/** The call threw. Ends the span. */
|
|
116
|
+
fail(err: unknown): void;
|
|
117
|
+
/** The call outlived its time budget. Ends the span; a late answer changes nothing. */
|
|
118
|
+
expire(): void;
|
|
119
|
+
}
|
|
120
|
+
/** How a tool call ended. */
|
|
121
|
+
export type ToolOutcome = "ok" | "error" | "blocked" | "unknown" | "parked" | "cancelled";
|
|
122
|
+
/** Who made a tool call. */
|
|
123
|
+
export type ToolOrigin = "agent" | "grader" | "script";
|
|
124
|
+
/** A tool call in flight. */
|
|
125
|
+
export interface ToolCallHandle {
|
|
126
|
+
/** The context the call runs in: its span active, marked as a tool call of its session. */
|
|
127
|
+
context: Context;
|
|
128
|
+
/** The tool the call reached, once its name is resolved. */
|
|
129
|
+
rename(tool: string): void;
|
|
130
|
+
/** How it ended, and — when blocked — the rule that blocked it. Ends the span. */
|
|
131
|
+
end(outcome: ToolOutcome, rule?: string): void;
|
|
132
|
+
}
|
|
133
|
+
/** What a model call's span is opened with. */
|
|
134
|
+
export interface ModelCallStart {
|
|
135
|
+
sessionId: string;
|
|
136
|
+
/** The state the call is made in; absent for a plain agent. */
|
|
137
|
+
state?: string;
|
|
138
|
+
role: "agent" | "grader";
|
|
139
|
+
/** The chat model the call runs on. */
|
|
140
|
+
model: unknown;
|
|
141
|
+
/** The id the call asks the endpoint for. */
|
|
142
|
+
requestModel?: string;
|
|
143
|
+
/** Prices, and the id a call whose response names none is priced as — what its `model-usage` event uses. */
|
|
144
|
+
pricing?: PricingTable;
|
|
145
|
+
pricingModel?: string;
|
|
146
|
+
}
|
|
147
|
+
/** What a tool call's span is opened with. */
|
|
148
|
+
export interface ToolCallStart {
|
|
149
|
+
sessionId: string;
|
|
150
|
+
state?: string;
|
|
151
|
+
/** The name the call was made with. */
|
|
152
|
+
tool: string;
|
|
153
|
+
/** The call's id, as its events carry it. */
|
|
154
|
+
callId: string;
|
|
155
|
+
origin: ToolOrigin;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The runtime's telemetry for one assembly: the spans of every turn its
|
|
159
|
+
* compositions run, a sub-workflow's children included, keyed by session.
|
|
160
|
+
*/
|
|
161
|
+
export declare class Telemetry {
|
|
162
|
+
#private;
|
|
163
|
+
/**
|
|
164
|
+
* Open a turn's span in the active context. Call {@link TurnHandle.end} or
|
|
165
|
+
* {@link TurnHandle.fail} exactly once.
|
|
166
|
+
*/
|
|
167
|
+
openTurn(start: TurnStart): TurnHandle;
|
|
168
|
+
/**
|
|
169
|
+
* Run `fn` as one turn: its span active throughout, settled from what `fn`
|
|
170
|
+
* returned, failed by what it threw (which still propagates).
|
|
171
|
+
*/
|
|
172
|
+
turn<T>(start: TurnStart, fn: () => Promise<T>, settled: (result: T) => TurnSettled): Promise<T>;
|
|
173
|
+
/**
|
|
174
|
+
* Follow the event stream: a state entered opens its span, a state left ends
|
|
175
|
+
* it, and a park, a failed automated run, an `on_error` route and a raise
|
|
176
|
+
* mark it. Events of a session with no open turn are ignored.
|
|
177
|
+
*/
|
|
178
|
+
observe(event: WorkflowLifecycleEvent): void;
|
|
179
|
+
/**
|
|
180
|
+
* The context a model or tool call's span is opened in: the active one when
|
|
181
|
+
* it is inside a tool call of the same session (a script's call); else the
|
|
182
|
+
* active one with its span replaced by the turn's — the open span of the state
|
|
183
|
+
* the call is made in; else, when the turn has opened no state yet (it
|
|
184
|
+
* continues in the state the session was in), that state's span, opened now
|
|
185
|
+
* and marked resumed; else the turn's own span (a call of a batch made in a
|
|
186
|
+
* state the batch has already left). A session with no open turn leaves the
|
|
187
|
+
* active context as it is.
|
|
188
|
+
*/
|
|
189
|
+
parentFor(sessionId: string, state?: string): Context;
|
|
190
|
+
/** Open a model call's span under {@link parentFor}. */
|
|
191
|
+
modelCall(start: ModelCallStart): ModelCallHandle;
|
|
192
|
+
/** Open a tool call's span under {@link parentFor}, marked as a tool call of its session. */
|
|
193
|
+
toolCall(start: ToolCallStart): ToolCallHandle;
|
|
194
|
+
}
|
|
195
|
+
/** Whether a tool's answer is the runtime's refusal of the call. */
|
|
196
|
+
export declare function isBlockedAnswer(answer: unknown): boolean;
|
|
197
|
+
/** Whether a tool's answer is an error the model reads. */
|
|
198
|
+
export declare function isErrorAnswer(answer: unknown): boolean;
|
|
199
|
+
/**
|
|
200
|
+
* The outcome of a tool call that threw `err`: a park (the session's own, or a
|
|
201
|
+
* sub-workflow's carried up through the call) is not the call's failure, a
|
|
202
|
+
* command to the parent graph is how the call answered, and a throw after the
|
|
203
|
+
* turn was cancelled is the cancellation's.
|
|
204
|
+
*/
|
|
205
|
+
export declare function thrownOutcomeOf(err: unknown, signal: AbortSignal | undefined): ToolOutcome;
|
|
206
|
+
/** The outcome of a tool call that settled with `answer`. */
|
|
207
|
+
export declare function toolOutcomeOf(answer: unknown): ToolOutcome;
|
|
208
|
+
/**
|
|
209
|
+
* Whether a tool's answer parks the session: it commits a pending input
|
|
210
|
+
* (`archmax_wait` accepted), a pending decision, or a pending delegation (a
|
|
211
|
+
* sub-workflow that stopped for a person).
|
|
212
|
+
*/
|
|
213
|
+
export declare function isParkingAnswer(answer: unknown): boolean;
|