@pikku/core 0.12.150 → 0.12.151
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/dist/function/function-runner.js +23 -0
- package/dist/function/trace-queue-service.d.ts +26 -0
- package/dist/function/trace-queue-service.js +48 -0
- package/dist/mesh.d.ts +2 -2
- package/dist/mesh.js +3 -3
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/mesh-auth.d.ts +3 -2
- package/dist/middleware/mesh-auth.js +7 -2
- package/dist/middleware/remote-jobs-secret.d.ts +1 -1
- package/dist/middleware/require-origin.d.ts +19 -0
- package/dist/middleware/require-origin.js +36 -2
- package/dist/services/deployment-service.d.ts +1 -1
- package/dist/services/incoming-webhook-service.d.ts +4 -2
- package/dist/services/incoming-webhook-service.js +4 -3
- package/dist/services/queue-webhook-service.js +7 -1
- package/dist/services/remote-jobs.d.ts +6 -1
- package/dist/services/scheduler-service.d.ts +3 -1
- package/dist/services/webhook-service.d.ts +2 -0
- package/dist/services/workflow-service.d.ts +4 -1
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/queue-identity-transport-tests.d.ts +18 -0
- package/dist/testing/queue-identity-transport-tests.js +162 -0
- package/dist/testing/queue-trace-conformance.d.ts +26 -0
- package/dist/testing/queue-trace-conformance.js +259 -0
- package/dist/testing/service-tests/channel-store-tests.js +11 -0
- package/dist/testing/service-tests/queued-workflow-harness.d.ts +18 -1
- package/dist/testing/service-tests/queued-workflow-harness.js +19 -3
- package/dist/testing/service-tests/workflow-service-tests.js +12 -0
- package/dist/testing/trace-matrix/assertions.d.ts +3 -0
- package/dist/testing/trace-matrix/assertions.js +190 -0
- package/dist/testing/trace-matrix/chain-harness.d.ts +119 -0
- package/dist/testing/trace-matrix/chain-harness.js +777 -0
- package/dist/testing/trace-matrix/dimensions.d.ts +55 -0
- package/dist/testing/trace-matrix/dimensions.js +305 -0
- package/dist/testing/trace-matrix/pairwise.d.ts +20 -0
- package/dist/testing/trace-matrix/pairwise.js +75 -0
- package/dist/testing/trace-matrix/report.d.ts +1 -0
- package/dist/testing/trace-matrix/report.js +16 -0
- package/dist/testing/trace-matrix/transports.d.ts +19 -0
- package/dist/testing/trace-matrix/transports.js +27 -0
- package/dist/testing/trace-matrix/workflow-cases.d.ts +24 -0
- package/dist/testing/trace-matrix/workflow-cases.js +147 -0
- package/dist/trace.d.ts +66 -0
- package/dist/trace.js +97 -0
- package/dist/types/core.types.d.ts +6 -2
- package/dist/wirings/addon/addon-reach.d.ts +3 -0
- package/dist/wirings/addon/addon-reach.js +9 -0
- package/dist/wirings/addon/define-plugin.d.ts +6 -0
- package/dist/wirings/addon/wire-addon.js +5 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +11 -0
- package/dist/wirings/agent/agent-finalize.d.ts +2 -0
- package/dist/wirings/agent/agent-finalize.js +1 -1
- package/dist/wirings/agent/agent-prepare.d.ts +3 -0
- package/dist/wirings/agent/agent-prepare.js +24 -8
- package/dist/wirings/agent/agent-rpc.js +1 -0
- package/dist/wirings/agent/agent-runner.js +3 -0
- package/dist/wirings/agent/agent-stream.js +4 -0
- package/dist/wirings/agent/voice-input.d.ts +1 -1
- package/dist/wirings/agent/voice-output.d.ts +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +4 -2
- package/dist/wirings/agent-scorer/agent-scorer-live.js +2 -2
- package/dist/wirings/channel/channel-common.d.ts +4 -1
- package/dist/wirings/channel/channel-common.js +3 -1
- package/dist/wirings/channel/channel-handler.js +2 -0
- package/dist/wirings/channel/channel-host-rpc.d.ts +1 -1
- package/dist/wirings/channel/channel-host-rpc.js +2 -2
- package/dist/wirings/channel/channel-rpc-responder.d.ts +7 -1
- package/dist/wirings/channel/channel-rpc-responder.js +2 -2
- package/dist/wirings/channel/channel-rpc-service.d.ts +1 -1
- package/dist/wirings/channel/channel-rpc-service.js +2 -2
- package/dist/wirings/channel/channel-rpc.types.d.ts +5 -2
- package/dist/wirings/channel/channel-rpc.types.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +4 -2
- package/dist/wirings/channel/channel-store.js +2 -2
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +16 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +3 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +27 -4
- package/dist/wirings/gateway/gateway-runner.js +3 -1
- package/dist/wirings/http/http-runner.d.ts +4 -4
- package/dist/wirings/http/http-runner.js +14 -18
- package/dist/wirings/http/http.types.d.ts +3 -3
- package/dist/wirings/mcp/mcp-runner.js +15 -5
- package/dist/wirings/queue/in-memory-queue-service.d.ts +1 -1
- package/dist/wirings/queue/in-memory-queue-service.js +8 -2
- package/dist/wirings/queue/index.d.ts +1 -0
- package/dist/wirings/queue/index.js +1 -0
- package/dist/wirings/queue/queue-runner.d.ts +3 -4
- package/dist/wirings/queue/queue-runner.js +8 -7
- package/dist/wirings/queue/queue-trace.d.ts +18 -0
- package/dist/wirings/queue/queue-trace.js +42 -0
- package/dist/wirings/queue/queue.types.d.ts +7 -0
- package/dist/wirings/queue/remote-queue-job.d.ts +1 -1
- package/dist/wirings/queue/remote-queue-job.js +5 -3
- package/dist/wirings/rpc/rpc-runner.d.ts +7 -1
- package/dist/wirings/rpc/rpc-runner.js +43 -21
- package/dist/wirings/rpc/rpc-types.d.ts +2 -0
- package/dist/wirings/scheduler/remote-scheduled-job.d.ts +1 -1
- package/dist/wirings/scheduler/remote-scheduled-job.js +2 -2
- package/dist/wirings/scheduler/scheduler-runner.d.ts +4 -4
- package/dist/wirings/scheduler/scheduler-runner.js +7 -6
- package/dist/wirings/trigger/pikku-trigger-service.js +7 -4
- package/dist/wirings/trigger/webhook-source-runner.d.ts +7 -1
- package/dist/wirings/trigger/webhook-source-runner.js +11 -3
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-runner.js +49 -30
- package/dist/wirings/workflow/index.d.ts +3 -1
- package/dist/wirings/workflow/index.js +1 -0
- package/dist/wirings/workflow/pikku-scenario-service.js +2 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +37 -40
- package/dist/wirings/workflow/pikku-workflow-service.js +122 -133
- package/dist/wirings/workflow/workflow-child-step.d.ts +2 -2
- package/dist/wirings/workflow/workflow-child-step.js +11 -4
- package/dist/wirings/workflow/workflow-compensation.d.ts +6 -0
- package/dist/wirings/workflow/workflow-compensation.js +15 -1
- package/dist/wirings/workflow/workflow-constants.d.ts +13 -0
- package/dist/wirings/workflow/workflow-constants.js +13 -0
- package/dist/wirings/workflow/workflow-dsl-pass.d.ts +2 -0
- package/dist/wirings/workflow/workflow-dsl-pass.js +27 -11
- package/dist/wirings/workflow/workflow-recovery.d.ts +131 -3
- package/dist/wirings/workflow/workflow-recovery.js +233 -7
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +1 -0
- package/dist/wirings/workflow/workflow-run-mirror.d.ts +4 -0
- package/dist/wirings/workflow/workflow-run-mirror.js +16 -0
- package/dist/wirings/workflow/workflow-run-status.d.ts +2 -0
- package/dist/wirings/workflow/workflow-run-status.js +13 -0
- package/dist/wirings/workflow/workflow-run-trace.d.ts +22 -0
- package/dist/wirings/workflow/workflow-run-trace.js +24 -0
- package/dist/wirings/workflow/workflow-step-claim.d.ts +18 -0
- package/dist/wirings/workflow/workflow-step-claim.js +47 -0
- package/dist/wirings/workflow/workflow-step-retry.d.ts +6 -2
- package/dist/wirings/workflow/workflow-step-retry.js +8 -3
- package/dist/wirings/workflow/workflow-wire.d.ts +12 -0
- package/dist/wirings/workflow/workflow-wire.js +33 -0
- package/dist/wirings/workflow/workflow.types.d.ts +16 -0
- package/package.json +2 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ConflictError, ForbiddenError, NotFoundError, UnauthorizedError, UnprocessableContentError, } from '../../errors/errors.js';
|
|
2
|
+
import { AbandonedError } from '../../function/abort-scope.js';
|
|
3
|
+
import { RemoteAddonAuthError } from '../../wirings/addon/remote-addon-auth.js';
|
|
4
|
+
import { RemoteAddonFailedError, RemoteAddonTimeoutError, } from '../../wirings/rpc/rpc-runner.js';
|
|
5
|
+
import { QueueJobDiscardedError } from '../../wirings/queue/queue-runner.js';
|
|
6
|
+
import { InMemoryWorkflowService } from '../../wirings/workflow/in-memory-workflow-service.js';
|
|
7
|
+
import { PikkuWorkflowService } from '../../wirings/workflow/pikku-workflow-service.js';
|
|
8
|
+
/** Sleeps go through the scheduler, as in a deployment, so the wake-up is driven by hand. */
|
|
9
|
+
export class ScheduledSleeps extends InMemoryWorkflowService {
|
|
10
|
+
scheduleSleep(...args) {
|
|
11
|
+
return PikkuWorkflowService.prototype['scheduleSleep'].apply(this, args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** What a step's RPC throws for an outcome: the class a real call would raise. */
|
|
15
|
+
export const outcomeError = (outcome) => {
|
|
16
|
+
switch (outcome) {
|
|
17
|
+
case 'throw-pikku-error':
|
|
18
|
+
case 'step-compensated':
|
|
19
|
+
case 'fan-out-sibling-failure':
|
|
20
|
+
return new ConflictError('refused');
|
|
21
|
+
case 'throw-plain-error':
|
|
22
|
+
case 'job-exhausted':
|
|
23
|
+
return new Error('boom');
|
|
24
|
+
case 'schema-invalid':
|
|
25
|
+
case 'job-poison':
|
|
26
|
+
return new UnprocessableContentError('schema refused the data');
|
|
27
|
+
case 'auth-mesh-jwt':
|
|
28
|
+
return new UnauthorizedError();
|
|
29
|
+
case 'auth-remote-addon':
|
|
30
|
+
return new RemoteAddonAuthError('far', 'resolved token was empty');
|
|
31
|
+
case 'permission-denied':
|
|
32
|
+
return new ForbiddenError();
|
|
33
|
+
case 'remote-4xx':
|
|
34
|
+
return new NotFoundError();
|
|
35
|
+
case 'remote-5xx':
|
|
36
|
+
case 'remote-network':
|
|
37
|
+
return new RemoteAddonFailedError('far', 'fn');
|
|
38
|
+
case 'remote-timeout':
|
|
39
|
+
return new RemoteAddonTimeoutError('far', 'fn', 2);
|
|
40
|
+
case 'job-discarded':
|
|
41
|
+
return new QueueJobDiscardedError('job', 'not wanted');
|
|
42
|
+
case 'abandoned':
|
|
43
|
+
return new AbandonedError('the caller left');
|
|
44
|
+
default:
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const isDsl = (workflow) => workflow.startsWith('dsl');
|
|
49
|
+
/**
|
|
50
|
+
* Registers a workflow named `flow-<id>` that reaches `step`, then has its last
|
|
51
|
+
* RPC meet `outcome`. Returns what brings the run to its end.
|
|
52
|
+
*/
|
|
53
|
+
export const defineRun = (h, run, child = false) => {
|
|
54
|
+
const { id, workflow, step, outcome } = run;
|
|
55
|
+
const queued = workflow.endsWith('-queued');
|
|
56
|
+
const failure = () => outcomeError(outcome);
|
|
57
|
+
let released = false;
|
|
58
|
+
let calls = 0;
|
|
59
|
+
const last = {
|
|
60
|
+
queued,
|
|
61
|
+
forward: async () => {
|
|
62
|
+
const error = failure();
|
|
63
|
+
if (error)
|
|
64
|
+
throw error;
|
|
65
|
+
if (step === 'retry' && ++calls === 1)
|
|
66
|
+
throw new Error('flaky');
|
|
67
|
+
return {};
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const undoable = step === 'compensation' || outcome === 'step-compensated'
|
|
71
|
+
? { compensate: async () => { } }
|
|
72
|
+
: {};
|
|
73
|
+
h.register(`first-${id}`, {
|
|
74
|
+
queued,
|
|
75
|
+
...undoable,
|
|
76
|
+
forward: async (_data, wire) => {
|
|
77
|
+
if (outcome === 'workflow-cancelled') {
|
|
78
|
+
await h.ws.cancelRun(wire.workflow?.runId ?? wire.workflowStep?.runId, h.rpc);
|
|
79
|
+
}
|
|
80
|
+
return {};
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
h.register(`last-${id}`, last);
|
|
84
|
+
h.register(`left-${id}`, { queued, forward: async () => ({}) });
|
|
85
|
+
const inner = child ? `inner-${id}` : `flow-${id}`;
|
|
86
|
+
if (isDsl(workflow)) {
|
|
87
|
+
h.defineDsl(inner, async (w) => {
|
|
88
|
+
await w.do('First', `first-${id}`, {});
|
|
89
|
+
if (step === 'sleep')
|
|
90
|
+
await w.sleep('Nap', 1);
|
|
91
|
+
if (step === 'suspend' && !released)
|
|
92
|
+
await w.suspend('Hold');
|
|
93
|
+
if (step === 'approval') {
|
|
94
|
+
const decision = await w.approval('Sign off', {
|
|
95
|
+
schema: {
|
|
96
|
+
'~standard': {
|
|
97
|
+
version: 1,
|
|
98
|
+
vendor: 'matrix',
|
|
99
|
+
validate: (value) => ({ value }),
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
if (decision.data?.ok === false) {
|
|
104
|
+
throw new ConflictError('the approval was rejected');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (step === 'fan-out') {
|
|
108
|
+
await Promise.all([
|
|
109
|
+
w.do('Left', `left-${id}`, {}),
|
|
110
|
+
w.do('Last', `last-${id}`, {}),
|
|
111
|
+
]);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
await w.do('Last', `last-${id}`, {}, step === 'retry' ? { retries: 2 } : undefined);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
h.defineGraph(inner, `first-${id}`, {
|
|
120
|
+
[`first-${id}`]: {
|
|
121
|
+
next: step === 'fan-out' ? [`left-${id}`, `last-${id}`] : `last-${id}`,
|
|
122
|
+
},
|
|
123
|
+
[`left-${id}`]: {},
|
|
124
|
+
[`last-${id}`]: step === 'retry' ? { retries: 2 } : {},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (child) {
|
|
128
|
+
h.defineDsl(`flow-${id}`, async (w) => w.do('Child', inner, {}));
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
/** Wakes whatever the run is waiting on, then lets it finish. */
|
|
132
|
+
settle: async (runId, wakeSleeps) => {
|
|
133
|
+
if (step === 'sleep')
|
|
134
|
+
await wakeSleeps();
|
|
135
|
+
if (step === 'suspend') {
|
|
136
|
+
released = true;
|
|
137
|
+
await h.ws.resumeWorkflow(runId);
|
|
138
|
+
}
|
|
139
|
+
if (step === 'approval') {
|
|
140
|
+
await h.ws.approveStep(runId, 'Sign off', {
|
|
141
|
+
ok: outcome !== 'approval-rejected',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
await h.pump();
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
};
|
package/dist/trace.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Logger } from './services/logger.js';
|
|
2
|
+
/** One invocation's place in a W3C trace. */
|
|
3
|
+
export type TraceContext = {
|
|
4
|
+
/** 32 lowercase hex characters, shared by every hop of the trace. */
|
|
5
|
+
traceId: string;
|
|
6
|
+
/** 16 lowercase hex characters, identifying this invocation. */
|
|
7
|
+
spanId: string;
|
|
8
|
+
/** The caller's span, when the trace was continued from another hop. */
|
|
9
|
+
parentSpanId?: string;
|
|
10
|
+
sampled: boolean;
|
|
11
|
+
};
|
|
12
|
+
/** Whether `value` is a usable trace id: 32 lowercase hex, not all zero. */
|
|
13
|
+
export declare const isValidTraceId: (value: unknown) => value is string;
|
|
14
|
+
/** A new trace, or a new span in `traceId` when one is given. */
|
|
15
|
+
export declare const createTrace: (traceId?: string) => TraceContext;
|
|
16
|
+
/**
|
|
17
|
+
* Reads a W3C `traceparent` header. Returns `undefined` for anything malformed,
|
|
18
|
+
* an all-zero id, version `ff`, or a version `00` header with extra fields.
|
|
19
|
+
*/
|
|
20
|
+
export declare const parseTraceparent: (header: unknown) => (Pick<TraceContext, 'traceId' | 'sampled'> & {
|
|
21
|
+
parentSpanId: string;
|
|
22
|
+
}) | undefined;
|
|
23
|
+
/** Formats `trace` as the `traceparent` of a call it makes: it is the parent. */
|
|
24
|
+
export declare const formatTraceparent: (trace: Pick<TraceContext, 'traceId' | 'spanId' | 'sampled'>) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolves the trace for an inbound HTTP request: a valid `traceId` from the
|
|
27
|
+
* runtime, then the `traceparent` header if the deployment opted in, then a new
|
|
28
|
+
* trace.
|
|
29
|
+
*
|
|
30
|
+
* knowledge: decisions/security/inbound-traceparent-is-ignored-until-the-caller-is-authenticated.md
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveHTTPTrace: (readHeader: () => unknown, logger: Logger, { traceId, trustInboundTraceparent, }: {
|
|
33
|
+
traceId?: string;
|
|
34
|
+
trustInboundTraceparent?: boolean;
|
|
35
|
+
}) => TraceContext;
|
|
36
|
+
/**
|
|
37
|
+
* Starts this hop's span in the trace a job, scheduled task or workflow run
|
|
38
|
+
* carried, or a new trace when it carried nothing usable. A carried value needs
|
|
39
|
+
* no signature: it names a trace, never an identity.
|
|
40
|
+
*/
|
|
41
|
+
export declare const continueTrace: (traceparent: unknown) => TraceContext;
|
|
42
|
+
/**
|
|
43
|
+
* Continues the caller's trace on an already-running invocation. Only for a
|
|
44
|
+
* caller that has been authenticated, and in place because the HTTP runner
|
|
45
|
+
* holds `wire.trace` for its error response.
|
|
46
|
+
*/
|
|
47
|
+
export declare const adoptTraceparent: (wire: {
|
|
48
|
+
traceId?: string;
|
|
49
|
+
trace?: TraceContext;
|
|
50
|
+
}, header: unknown) => void;
|
|
51
|
+
/** `logger` scoped to a trace, so what it writes can be found by that id. */
|
|
52
|
+
export declare const tracedLogger: (logger: Logger, traceId?: string) => Logger;
|
|
53
|
+
/** The wire fields for a hop that continues `traceparent`, or starts a new trace. */
|
|
54
|
+
export declare const traceWire: (traceparent?: unknown) => {
|
|
55
|
+
traceId: string;
|
|
56
|
+
trace: TraceContext;
|
|
57
|
+
};
|
|
58
|
+
/** {@link traceWire} for a child of `parent`, when there is a parent. */
|
|
59
|
+
export declare const childTraceWire: (parent: TraceContext | undefined) => {
|
|
60
|
+
traceId: string;
|
|
61
|
+
trace: TraceContext;
|
|
62
|
+
};
|
|
63
|
+
/** The `traceparent` for a call made from `wire`, if it is in a W3C trace. */
|
|
64
|
+
export declare const outgoingTraceparent: (wire: {
|
|
65
|
+
trace?: TraceContext;
|
|
66
|
+
}) => string | undefined;
|
package/dist/trace.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const TRACE_ID = /^[0-9a-f]{32}$/;
|
|
2
|
+
const TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/;
|
|
3
|
+
const ALL_ZERO = /^0+$/;
|
|
4
|
+
const randomHex = (bytes) => {
|
|
5
|
+
const hex = Array.from(globalThis.crypto.getRandomValues(new Uint8Array(bytes)), (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
6
|
+
// All zeroes means "invalid" in W3C, so it can never be issued.
|
|
7
|
+
return ALL_ZERO.test(hex) ? randomHex(bytes) : hex;
|
|
8
|
+
};
|
|
9
|
+
/** Whether `value` is a usable trace id: 32 lowercase hex, not all zero. */
|
|
10
|
+
export const isValidTraceId = (value) => typeof value === 'string' && TRACE_ID.test(value) && !ALL_ZERO.test(value);
|
|
11
|
+
/** A new trace, or a new span in `traceId` when one is given. */
|
|
12
|
+
export const createTrace = (traceId) => ({
|
|
13
|
+
traceId: traceId ?? randomHex(16),
|
|
14
|
+
spanId: randomHex(8),
|
|
15
|
+
sampled: true,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Reads a W3C `traceparent` header. Returns `undefined` for anything malformed,
|
|
19
|
+
* an all-zero id, version `ff`, or a version `00` header with extra fields.
|
|
20
|
+
*/
|
|
21
|
+
export const parseTraceparent = (header) => {
|
|
22
|
+
if (typeof header !== 'string')
|
|
23
|
+
return undefined;
|
|
24
|
+
const match = TRACEPARENT.exec(header);
|
|
25
|
+
if (!match)
|
|
26
|
+
return undefined;
|
|
27
|
+
const [, version, traceId, parentSpanId, flags, extra] = match;
|
|
28
|
+
if (version === 'ff' || (version === '00' && extra !== undefined)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (ALL_ZERO.test(traceId) || ALL_ZERO.test(parentSpanId))
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
traceId: traceId,
|
|
35
|
+
parentSpanId: parentSpanId,
|
|
36
|
+
sampled: (Number.parseInt(flags, 16) & 1) === 1,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/** Formats `trace` as the `traceparent` of a call it makes: it is the parent. */
|
|
40
|
+
export const formatTraceparent = (trace) => `00-${trace.traceId}-${trace.spanId}-${trace.sampled ? '01' : '00'}`;
|
|
41
|
+
/**
|
|
42
|
+
* Resolves the trace for an inbound HTTP request: a valid `traceId` from the
|
|
43
|
+
* runtime, then the `traceparent` header if the deployment opted in, then a new
|
|
44
|
+
* trace.
|
|
45
|
+
*
|
|
46
|
+
* knowledge: decisions/security/inbound-traceparent-is-ignored-until-the-caller-is-authenticated.md
|
|
47
|
+
*/
|
|
48
|
+
export const resolveHTTPTrace = (readHeader, logger, { traceId, trustInboundTraceparent, }) => {
|
|
49
|
+
if (traceId !== undefined) {
|
|
50
|
+
if (isValidTraceId(traceId))
|
|
51
|
+
return createTrace(traceId);
|
|
52
|
+
logger.warn('Ignoring a traceId that is not 32 lowercase hex characters');
|
|
53
|
+
}
|
|
54
|
+
if (trustInboundTraceparent) {
|
|
55
|
+
let header;
|
|
56
|
+
try {
|
|
57
|
+
header = readHeader();
|
|
58
|
+
}
|
|
59
|
+
catch { }
|
|
60
|
+
const inbound = parseTraceparent(header);
|
|
61
|
+
if (inbound)
|
|
62
|
+
return { ...inbound, spanId: randomHex(8) };
|
|
63
|
+
}
|
|
64
|
+
return createTrace();
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Starts this hop's span in the trace a job, scheduled task or workflow run
|
|
68
|
+
* carried, or a new trace when it carried nothing usable. A carried value needs
|
|
69
|
+
* no signature: it names a trace, never an identity.
|
|
70
|
+
*/
|
|
71
|
+
export const continueTrace = (traceparent) => {
|
|
72
|
+
const carried = parseTraceparent(traceparent);
|
|
73
|
+
return carried ? { ...carried, spanId: randomHex(8) } : createTrace();
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Continues the caller's trace on an already-running invocation. Only for a
|
|
77
|
+
* caller that has been authenticated, and in place because the HTTP runner
|
|
78
|
+
* holds `wire.trace` for its error response.
|
|
79
|
+
*/
|
|
80
|
+
export const adoptTraceparent = (wire, header) => {
|
|
81
|
+
const inbound = parseTraceparent(header);
|
|
82
|
+
if (!inbound)
|
|
83
|
+
return;
|
|
84
|
+
wire.traceId = inbound.traceId;
|
|
85
|
+
wire.trace = Object.assign(wire.trace ?? createTrace(inbound.traceId), inbound);
|
|
86
|
+
};
|
|
87
|
+
/** `logger` scoped to a trace, so what it writes can be found by that id. */
|
|
88
|
+
export const tracedLogger = (logger, traceId) => (traceId && logger.scope?.(traceId)) || logger;
|
|
89
|
+
/** The wire fields for a hop that continues `traceparent`, or starts a new trace. */
|
|
90
|
+
export const traceWire = (traceparent) => {
|
|
91
|
+
const trace = continueTrace(traceparent);
|
|
92
|
+
return { traceId: trace.traceId, trace };
|
|
93
|
+
};
|
|
94
|
+
/** {@link traceWire} for a child of `parent`, when there is a parent. */
|
|
95
|
+
export const childTraceWire = (parent) => traceWire(parent && formatTraceparent(parent));
|
|
96
|
+
/** The `traceparent` for a call made from `wire`, if it is in a W3C trace. */
|
|
97
|
+
export const outgoingTraceparent = (wire) => wire.trace && formatTraceparent(wire.trace);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { AbortScope } from '../function/abort-scope.js';
|
|
2
|
+
import type { TraceContext } from '../trace.js';
|
|
3
|
+
export type { TraceContext };
|
|
2
4
|
import type { IncomingWebhookService } from '../services/incoming-webhook-service.js';
|
|
3
5
|
import type { TriggerSourceStore } from '../services/trigger-source-store.js';
|
|
4
6
|
import type { LeaseService } from '../services/lease-service.js';
|
|
@@ -88,7 +90,7 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
88
90
|
/** Refuse a secret that declares no `allowedHosts` rather than treating it as unrestricted. */
|
|
89
91
|
requireAllowedHosts?: boolean;
|
|
90
92
|
};
|
|
91
|
-
workflow?: WorkflowServiceConfig
|
|
93
|
+
workflow?: Partial<WorkflowServiceConfig>;
|
|
92
94
|
webhook?: WebhookServiceConfig;
|
|
93
95
|
postgres?: PostgresConfig;
|
|
94
96
|
} & Config;
|
|
@@ -255,8 +257,10 @@ export type PikkuWire<In = unknown, Out = unknown, HasInitialSession extends boo
|
|
|
255
257
|
* sets it; services that log fall back to the singleton logger.
|
|
256
258
|
*/
|
|
257
259
|
logger: Logger;
|
|
258
|
-
/** Trace ID for distributed tracing — propagated across mesh RPC calls via the
|
|
260
|
+
/** Trace ID for distributed tracing — propagated across mesh RPC calls via the traceparent header */
|
|
259
261
|
traceId: string;
|
|
262
|
+
/** This invocation's place in the trace, when it has a W3C one. */
|
|
263
|
+
trace: TraceContext;
|
|
260
264
|
functionId: string;
|
|
261
265
|
addonNamespace: string;
|
|
262
266
|
http: PikkuHTTP<In>;
|
|
@@ -5,6 +5,9 @@ export declare const addonCallerOf: (wire: PikkuRawWire) => string | undefined;
|
|
|
5
5
|
export declare class AddonNotUsedError extends PikkuError {
|
|
6
6
|
constructor(caller: string, target: string);
|
|
7
7
|
}
|
|
8
|
+
export declare class AddonUsesShadowedError extends PikkuError {
|
|
9
|
+
constructor(name: string, target: string);
|
|
10
|
+
}
|
|
8
11
|
/**
|
|
9
12
|
* The name an addon's call resolves to on this host, through its `uses`.
|
|
10
13
|
*
|
|
@@ -29,6 +29,15 @@ addError(AddonNotUsedError, {
|
|
|
29
29
|
status: 403,
|
|
30
30
|
message: 'Addon called another addon it does not use.',
|
|
31
31
|
});
|
|
32
|
+
export class AddonUsesShadowedError extends PikkuError {
|
|
33
|
+
constructor(name, target) {
|
|
34
|
+
super(`Addon '${name}' maps its own name in 'uses' to '${target}', but a call to '${name}:<function>' always reaches the addon itself, so the mapping can never be used. Mount the addon under another name.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
addError(AddonUsesShadowedError, {
|
|
38
|
+
status: 500,
|
|
39
|
+
message: 'Addon uses maps its own name.',
|
|
40
|
+
});
|
|
32
41
|
/**
|
|
33
42
|
* The name an addon's call resolves to on this host, through its `uses`.
|
|
34
43
|
*
|
|
@@ -32,6 +32,12 @@ type StudioScreenBase = {
|
|
|
32
32
|
* Lowercase letters, digits and hyphens, starting with a letter. Leave it out and the chat is unchanged.
|
|
33
33
|
*/
|
|
34
34
|
agent?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether Studio's general Chat tab shows on this screen, beside the
|
|
37
|
+
* screen's agent tab. Defaults to `true`. `false` hides it; with no `agent`
|
|
38
|
+
* the screen then has no chat at all.
|
|
39
|
+
*/
|
|
40
|
+
defaultChat?: boolean;
|
|
35
41
|
} & ({
|
|
36
42
|
/** `'studio'` gives `/<path>`, `'team'` gives `/<team>/<path>`. */
|
|
37
43
|
scope: 'studio' | 'team';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { pikkuState } from '../../pikku-state.js';
|
|
2
2
|
import { getTagGroups } from '../../utils.js';
|
|
3
|
+
import { AddonUsesShadowedError } from './addon-reach.js';
|
|
3
4
|
/**
|
|
4
5
|
* Installs an addon into this project: its functions, wirings and scopes become
|
|
5
6
|
* part of the app, under the namespace and options given here.
|
|
@@ -7,6 +8,10 @@ import { getTagGroups } from '../../utils.js';
|
|
|
7
8
|
* @example snippet: addonWiring
|
|
8
9
|
*/
|
|
9
10
|
export const wireAddon = (config) => {
|
|
11
|
+
const shadowed = config.uses?.[config.name];
|
|
12
|
+
if (shadowed !== undefined && shadowed !== config.name) {
|
|
13
|
+
throw new AddonUsesShadowedError(config.name, shadowed);
|
|
14
|
+
}
|
|
10
15
|
pikkuState(null, 'addons', 'packages').set(config.name, {
|
|
11
16
|
package: config.package,
|
|
12
17
|
rpcEndpoint: config.rpcEndpoint,
|
|
@@ -51,6 +51,17 @@ export type WireRemoteAddonConfig = {
|
|
|
51
51
|
* knowledge: decisions/security/wire-addon-expose-selects-the-rpc-surface.md
|
|
52
52
|
*/
|
|
53
53
|
expose?: boolean | string[];
|
|
54
|
+
/**
|
|
55
|
+
* A package installed in this project that carries the screens and
|
|
56
|
+
* contributors shown under this name, when they live apart from the contract
|
|
57
|
+
* package. Read at build time, never at runtime. `ui` mounts its screens;
|
|
58
|
+
* `contributors` opts in to the ones it registers.
|
|
59
|
+
*/
|
|
60
|
+
local?: {
|
|
61
|
+
package: string;
|
|
62
|
+
ui?: boolean;
|
|
63
|
+
contributors?: string[];
|
|
64
|
+
};
|
|
54
65
|
/** Milliseconds a call may take before it is aborted. Defaults to {@link DEFAULT_REMOTE_ADDON_TIMEOUT_MS}. */
|
|
55
66
|
timeoutMs?: number;
|
|
56
67
|
/** Extra headers for every call to the host. Cannot replace the auth, trace or contract headers. */
|
|
@@ -12,6 +12,8 @@ export type RunUsage = {
|
|
|
12
12
|
* a scorer is shown is exactly what was stored — including the redactions.
|
|
13
13
|
*/
|
|
14
14
|
export type FinalizedRun = {
|
|
15
|
+
/** The trace the run's scoring jobs stay in. */
|
|
16
|
+
traceparent?: string;
|
|
15
17
|
runId: string;
|
|
16
18
|
agentName: string;
|
|
17
19
|
threadId: string;
|
|
@@ -130,7 +130,7 @@ export const finalizeAgentRun = async (agentRunState, run) => {
|
|
|
130
130
|
// Best-effort and last: the client already has its answer, so a grading
|
|
131
131
|
// failure must not surface as a failed run.
|
|
132
132
|
try {
|
|
133
|
-
await scoreFinishedRun(snapshot, services);
|
|
133
|
+
await scoreFinishedRun(snapshot, services, run.traceparent);
|
|
134
134
|
}
|
|
135
135
|
catch (error) {
|
|
136
136
|
services.logger?.error(`[pikku] Live scoring failed for run ${run.runId}`, error);
|
|
@@ -3,6 +3,7 @@ import type { CoreAgent, AgentInput, AgentToolDef, AgentMessage, AgentStreamChan
|
|
|
3
3
|
import type { AgentRunnerParams, AgentRunnerService } from '../../services/agent-runner-service.js';
|
|
4
4
|
import { PikkuError } from '../../errors/error-handler.js';
|
|
5
5
|
import type { SessionService } from '../../services/user-session-service.js';
|
|
6
|
+
import { type TraceContext } from '../../trace.js';
|
|
6
7
|
/**
|
|
7
8
|
* Per-request context for running an agent: the caller's session, credential access and, for
|
|
8
9
|
* a sessionless request, the minted anonymous owner id.
|
|
@@ -13,6 +14,8 @@ export type RunAgentParams = {
|
|
|
13
14
|
getCredential?: GetCredential;
|
|
14
15
|
/** Ephemeral owner identity minted for a sessionless request; never client-supplied, never reused across requests. */
|
|
15
16
|
anonymousOwnerResourceId?: string;
|
|
17
|
+
/** The caller's trace. Each tool call is a span in it. */
|
|
18
|
+
trace?: TraceContext;
|
|
16
19
|
};
|
|
17
20
|
export declare function resolveSessionPrincipal(params: RunAgentParams, sessionScope: SessionScope | undefined): string | undefined;
|
|
18
21
|
export declare function resolveOwnerResourceId(params: RunAgentParams, sessionScope: SessionScope | undefined, requestedResourceId: string): string;
|
|
@@ -11,6 +11,7 @@ import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc
|
|
|
11
11
|
import { getOrCreatePackageSingletonServices } from '../../wirings/addon/addon-runner.js';
|
|
12
12
|
import { resolveMemoryServices, loadContextMessages, trimMessages, } from './agent-memory.js';
|
|
13
13
|
import { resolveModelConfig } from './agent-model-config.js';
|
|
14
|
+
import { childTraceWire, createTrace, outgoingTraceparent, tracedLogger, } from '../../trace.js';
|
|
14
15
|
export function resolveSessionPrincipal(params, sessionScope) {
|
|
15
16
|
const session = params.sessionService?.get();
|
|
16
17
|
if ((sessionScope ?? 'user') === 'org') {
|
|
@@ -321,6 +322,8 @@ export function buildSubAgentRunInput(message, threadId, resourceId, parentConte
|
|
|
321
322
|
export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, agentMiddlewares, agentMode, parentContext) {
|
|
322
323
|
const singletonServices = getSingletonServices();
|
|
323
324
|
const tools = [];
|
|
325
|
+
// Every tool of a run sits under one trace, whoever started the run.
|
|
326
|
+
const trace = params.trace ?? createTrace();
|
|
324
327
|
const missingRpcs = [];
|
|
325
328
|
const approvalPolicy = streamContext?.options?.requiresToolApproval ?? 'explicit';
|
|
326
329
|
const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName];
|
|
@@ -442,9 +445,14 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
442
445
|
approvalDescriptionFn,
|
|
443
446
|
readonly: fnMeta?.readonly || undefined,
|
|
444
447
|
execute: async (toolInput, options) => {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
:
|
|
448
|
+
// The call below is the tool's span, under the run's.
|
|
449
|
+
const wire = {
|
|
450
|
+
traceId: trace.traceId,
|
|
451
|
+
trace,
|
|
452
|
+
...(params.sessionService
|
|
453
|
+
? createMiddlewareSessionWireProps(params.sessionService)
|
|
454
|
+
: {}),
|
|
455
|
+
};
|
|
448
456
|
if (options?.abortScope)
|
|
449
457
|
wire.abortScope = options.abortScope;
|
|
450
458
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
@@ -594,13 +602,21 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
594
602
|
if (!workflowService) {
|
|
595
603
|
throw new Error(`workflowService is not configured — cannot run workflow tool '${workflowName}'`);
|
|
596
604
|
}
|
|
597
|
-
const wire =
|
|
598
|
-
|
|
599
|
-
|
|
605
|
+
const wire = {
|
|
606
|
+
...childTraceWire(trace),
|
|
607
|
+
...(params.sessionService
|
|
608
|
+
? createMiddlewareSessionWireProps(params.sessionService)
|
|
609
|
+
: {}),
|
|
610
|
+
};
|
|
600
611
|
if (options?.abortScope)
|
|
601
612
|
wire.abortScope = options.abortScope;
|
|
602
613
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
603
|
-
return workflowService.runToCompletion(workflowName, toolInput, rpcService, {
|
|
614
|
+
return workflowService.runToCompletion(workflowName, toolInput, rpcService, {
|
|
615
|
+
wire: {
|
|
616
|
+
type: 'internal',
|
|
617
|
+
traceparent: outgoingTraceparent(wire),
|
|
618
|
+
},
|
|
619
|
+
});
|
|
604
620
|
},
|
|
605
621
|
});
|
|
606
622
|
}
|
|
@@ -619,7 +635,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
619
635
|
...err.payload,
|
|
620
636
|
};
|
|
621
637
|
}
|
|
622
|
-
singletonServices.logger.error(`AI agent tool '${tool.name}' threw during execute()`, err);
|
|
638
|
+
tracedLogger(singletonServices.logger, trace.traceId).error(`AI agent tool '${tool.name}' threw during execute()`, err);
|
|
623
639
|
throw err;
|
|
624
640
|
}
|
|
625
641
|
};
|
|
@@ -14,6 +14,7 @@ export const createAgentRPC = (wire, options) => {
|
|
|
14
14
|
const params = () => ({
|
|
15
15
|
sessionService: options.sessionService,
|
|
16
16
|
getCredential: wire.getCredential?.bind(wire),
|
|
17
|
+
trace: wire.trace,
|
|
17
18
|
});
|
|
18
19
|
const streamingChannel = () => {
|
|
19
20
|
const channel = wire.channel;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { outgoingTraceparent } from '../../trace.js';
|
|
1
2
|
import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './agent-memory.js';
|
|
2
3
|
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourcePrincipalOwner, assertRunBelongsToAgent, assertAgentAuthorized, resolveAgentRunner, } from './agent-prepare.js';
|
|
3
4
|
import { checkForApprovals, appendStepMessages } from './agent-stream.js';
|
|
@@ -224,6 +225,7 @@ export async function runAgent(agentName, input, params, agentSessionMap) {
|
|
|
224
225
|
uiSpec: structuredOutput.uiSpec,
|
|
225
226
|
});
|
|
226
227
|
await finalizeAgentRun(agentRunState, {
|
|
228
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
227
229
|
runId,
|
|
228
230
|
agentName,
|
|
229
231
|
threadId,
|
|
@@ -557,6 +559,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
557
559
|
steps: accumulatedSteps,
|
|
558
560
|
});
|
|
559
561
|
await finalizeAgentRun(agentRunState, {
|
|
562
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
560
563
|
runId: run.runId,
|
|
561
564
|
agentName: resolvedName,
|
|
562
565
|
threadId: run.threadId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { outgoingTraceparent } from '../../trace.js';
|
|
1
2
|
import { finalizeAgentRun, lastUserMessageText } from './agent-finalize.js';
|
|
2
3
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
3
4
|
import { applyInputMiddleware, describeApprovals } from './agent-turn.js';
|
|
@@ -185,6 +186,7 @@ const warnUnstreamedOutputHooks = (agentName, agentMiddlewares, logger) => {
|
|
|
185
186
|
};
|
|
186
187
|
async function postStreamCleanup(persistingChannel, agentRunState, runId, run) {
|
|
187
188
|
await finalizeAgentRun(agentRunState, {
|
|
189
|
+
traceparent: run.traceparent,
|
|
188
190
|
runId,
|
|
189
191
|
agentName: run.agentName,
|
|
190
192
|
threadId: run.threadId,
|
|
@@ -619,6 +621,7 @@ export async function streamAgent(agentName, input, channel, params, agentSessio
|
|
|
619
621
|
return persistingChannel.fullText;
|
|
620
622
|
}
|
|
621
623
|
await postStreamCleanup(persistingChannel, agentRunState, runId, {
|
|
624
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
622
625
|
agentName,
|
|
623
626
|
threadId,
|
|
624
627
|
resourceId: input.resourceId,
|
|
@@ -1019,6 +1022,7 @@ async function continueAfterToolResult(run, agent, packageName, resolvedName, st
|
|
|
1019
1022
|
return;
|
|
1020
1023
|
}
|
|
1021
1024
|
await postStreamCleanup(persistingChannel, agentRunState, run.runId, {
|
|
1025
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
1022
1026
|
...run,
|
|
1023
1027
|
input: lastUserMessageText(runnerParams.messages),
|
|
1024
1028
|
});
|
|
@@ -75,7 +75,7 @@ export declare const voiceInput: (config?: {
|
|
|
75
75
|
secrets?: {
|
|
76
76
|
requireAllowedHosts?: boolean;
|
|
77
77
|
};
|
|
78
|
-
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig
|
|
78
|
+
workflow?: Partial<import("../workflow/workflow.types.js").WorkflowServiceConfig>;
|
|
79
79
|
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
80
80
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
81
81
|
}>>;
|
|
@@ -93,7 +93,7 @@ export declare const voiceOutput: (config?: {
|
|
|
93
93
|
secrets?: {
|
|
94
94
|
requireAllowedHosts?: boolean;
|
|
95
95
|
};
|
|
96
|
-
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig
|
|
96
|
+
workflow?: Partial<import("../workflow/workflow.types.js").WorkflowServiceConfig>;
|
|
97
97
|
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
98
98
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
99
99
|
}>>;
|
|
@@ -10,6 +10,8 @@ import { type ScorerInput } from './agent-scorer.types.js';
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const scoreFinishedRun: (run: ScorerInput, services: Pick<CoreSingletonServices, 'logger'> & {
|
|
12
12
|
queueService?: {
|
|
13
|
-
add: (queueName: string, data: unknown
|
|
13
|
+
add: (queueName: string, data: unknown, options?: {
|
|
14
|
+
traceparent?: string;
|
|
15
|
+
}) => Promise<any>;
|
|
14
16
|
};
|
|
15
|
-
}) => Promise<void>;
|
|
17
|
+
}, traceparent?: string) => Promise<void>;
|
|
@@ -9,7 +9,7 @@ import { SCORER_LANE_QUEUES } from './agent-scorer.types.js';
|
|
|
9
9
|
* also strictly best-effort: the client already has its answer, so nothing here
|
|
10
10
|
* may fail the run.
|
|
11
11
|
*/
|
|
12
|
-
export const scoreFinishedRun = async (run, services) => {
|
|
12
|
+
export const scoreFinishedRun = async (run, services, traceparent) => {
|
|
13
13
|
const scorers = scorersForAgent(run.agentName, services.logger).filter(
|
|
14
14
|
// A reference-based judge grades against an answer key, and live traffic
|
|
15
15
|
// has none.
|
|
@@ -29,7 +29,7 @@ export const scoreFinishedRun = async (run, services) => {
|
|
|
29
29
|
scorerName: scorer.name,
|
|
30
30
|
// No reference: a live run has no answer key.
|
|
31
31
|
reference: undefined,
|
|
32
|
-
});
|
|
32
|
+
}, traceparent ? { traceparent } : undefined);
|
|
33
33
|
}
|
|
34
34
|
catch (error) {
|
|
35
35
|
services.logger?.error(`[pikku] Failed to enqueue the '${scorer.name}' grade of run ${run.runId}`, { error });
|
|
@@ -2,7 +2,8 @@ import type { CoreSingletonServices } from '../../types/core.types.js';
|
|
|
2
2
|
import type { MiddlewareMetadata } from '../../middleware/middleware.types.js';
|
|
3
3
|
import type { CoreChannel, ChannelMessageMeta } from './channel.types.js';
|
|
4
4
|
import { type PikkuSessionService } from '../../services/user-session-service.js';
|
|
5
|
-
|
|
5
|
+
import { type TraceContext } from '../../trace.js';
|
|
6
|
+
export declare const runChannelLifecycleWithMiddleware: ({ channelConfig, meta, lifecycleConfig, lifecycleType, services, channel, data, channelMiddlewareMeta, userSession, wireServices, trace, }: {
|
|
6
7
|
channelConfig: CoreChannel<unknown, any>;
|
|
7
8
|
meta: ChannelMessageMeta;
|
|
8
9
|
lifecycleConfig: any;
|
|
@@ -11,6 +12,8 @@ export declare const runChannelLifecycleWithMiddleware: ({ channelConfig, meta,
|
|
|
11
12
|
channel: any;
|
|
12
13
|
data?: unknown;
|
|
13
14
|
channelMiddlewareMeta?: MiddlewareMetadata[];
|
|
15
|
+
/** The connection's trace; the lifecycle hook is a span in it. */
|
|
16
|
+
trace?: TraceContext;
|
|
14
17
|
/**
|
|
15
18
|
* Established while the socket was upgrading, so `onConnect` can tell who
|
|
16
19
|
* just connected.
|