@exellix/graph-engine 7.3.3 → 7.3.9
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 +100 -5
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -1
- package/dist/src/integrations/ActivixGraphRunIntegration.d.ts +3 -2
- package/dist/src/integrations/ActivixGraphRunIntegration.js +24 -39
- package/dist/src/integrations/ActivixNodeActivityIntegration.d.ts +2 -1
- package/dist/src/integrations/ActivixNodeActivityIntegration.js +30 -50
- package/dist/src/integrations/activixExellixShared.d.ts +58 -0
- package/dist/src/integrations/activixExellixShared.js +59 -0
- package/dist/src/integrations/createActivixExellixIntegration.d.ts +3 -0
- package/dist/src/integrations/createActivixExellixIntegration.js +2 -1
- package/dist/src/integrations/createActivixFromEnv.js +12 -2
- package/dist/src/integrations/ensureActivixOnRuntimeObjects.d.ts +4 -0
- package/dist/src/integrations/ensureActivixOnRuntimeObjects.js +7 -0
- package/dist/src/runtime/ExellixGraphRuntime.js +3 -2
- package/dist/src/runtime/graphEngineLogMeta.d.ts +16 -0
- package/dist/src/runtime/graphEngineLogMeta.js +75 -0
- package/dist/src/runtime/graphEngineLogxer.d.ts +1 -0
- package/dist/src/runtime/graphEngineLogxer.js +38 -6
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ A minimal, focused SDK for executing graphs in the exellix ecosystem.
|
|
|
35
35
|
| Task-node `conditions` + conditional `modelConfig.cases` (runx) | [`.docs/task-node-conditions-evaluation.md`](.docs/task-node-conditions-evaluation.md) |
|
|
36
36
|
| **Model profile aliases** (7.x: graph = profile names, runtime = concrete models) | [`BREAKING-CHANGES.md`](BREAKING-CHANGES.md) §7.0.0, [`.docs/ai-tasks-model-profile-aliases-7x.md`](.docs/ai-tasks-model-profile-aliases-7x.md) (ai-tasks), [`.docs/fr-model-alias-descriptors.md`](.docs/fr-model-alias-descriptors.md) (upstream FRs) |
|
|
37
37
|
| Platform vs implementation (no domain operators in schema) | [`.docs/platform-generic-vs-implementation.md`](.docs/platform-generic-vs-implementation.md) |
|
|
38
|
+
| Activix records, `runContext`, collection tracking (`@x12i/activix` 8.4+) | [`.docs/activix-records.md`](.docs/activix-records.md) |
|
|
38
39
|
| Bundled graph examples & bundle README | [`graphs/README.md`](graphs/README.md) |
|
|
39
40
|
|
|
40
41
|
The **`runTask`** wire contract (identity, canonical **`input`**, optional extra ai-tasks PRE/POST utility calls vs `executionPipeline`) is summarized later under **Run identity** and **`runTask` request contract**, and expanded in the graph format doc’s [**Graph JSON vs outbound `runTask`**](.docs/exellix-graph-engine-format.md#graph-json-vs-outbound-runtask) section. Graph-engine integrates with **`@exellix/ai-tasks`** at the semver range declared in **`package.json`** (currently **`^7.6.4`**); use your **lockfile** as the tested line. Variable buckets align with ai-tasks **≥ 7.6.2** (two-scope passthrough). There is **no** minimum graph-engine ↔ ai-tasks matrix published inside ai-tasks — follow dependency semver and upstream **`CHANGELOG.md`**. Graph-engine does **not** import or invoke the Xynthesis SDK directly.
|
|
@@ -259,7 +260,7 @@ const markdown = playgroundReporter.getMarkdown();
|
|
|
259
260
|
|
|
260
261
|
- **Results:** `ExecuteGraphResult` includes both **`jobId`** and **`taskId`** so callers and logs can correlate host scope vs engine run instance.
|
|
261
262
|
|
|
262
|
-
- **Activix:** Graph-run
|
|
263
|
+
- **Activix (`@x12i/activix` 8.4+):** Graph-run and node integrations pass a top-level **`runContext`** on every `startRecord` (`sessionId` = **`jobId`**, plus **`taskId`**, **`graphId`**, and for nodes **`nodeId`** / **`skillKey`**). Activix owns **collection tracking state** (`track` / `off` on legend rows) — graph-engine **always** calls lifecycle APIs; do not branch on persistence in app code. In-process maps correlate start → complete/fail by **`activityId`** (`jobId:graphId:taskId` for graph runs; `graphId:nodeId:taskId` for nodes). Query rows via **`activixClient.getJobActivities`** (see [Activix integration](#activix-integration-graph-run-record)).
|
|
263
264
|
|
|
264
265
|
- **Helpers:** **`assertHostJobId`** and **`newGraphRunTaskId`** are exported from the package root for hosts/tests that build inputs outside `executeGraph`.
|
|
265
266
|
|
|
@@ -428,12 +429,81 @@ Output shape (per item key):
|
|
|
428
429
|
|
|
429
430
|
## Activix integration (graph run record)
|
|
430
431
|
|
|
431
|
-
|
|
432
|
+
Graph-engine depends on **`@x12i/activix`** (see **`package.json`**, currently **8.4.x**). Full wiring guide: [`.docs/activix-records.md`](.docs/activix-records.md). Activix README (collection tracking, `getJobActivities`, phased `outer` / `inner` I/O): `node_modules/@x12i/activix/README.md`.
|
|
433
|
+
|
|
434
|
+
### Wiring (recommended)
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
import {
|
|
438
|
+
createActivixFromEnv,
|
|
439
|
+
createActivixExellixIntegration,
|
|
440
|
+
createExellixGraphRuntime,
|
|
441
|
+
resolveActivixExellixCollectionNamesFromEnv,
|
|
442
|
+
} from '@exellix/graph-engine';
|
|
443
|
+
import { buildExellixGraphRuntimeObjects } from '@exellix/graph-engine/testkit';
|
|
444
|
+
|
|
445
|
+
const ax = createActivixFromEnv({ strict: true });
|
|
446
|
+
await ax.init();
|
|
447
|
+
|
|
448
|
+
const { graphRuns, nodeActivity } = resolveActivixExellixCollectionNamesFromEnv();
|
|
449
|
+
const { eventEmitter, activixClient } = createActivixExellixIntegration(ax, {
|
|
450
|
+
activixGraphRun: { collection: graphRuns },
|
|
451
|
+
activixNodeActivity: {
|
|
452
|
+
collection: nodeActivity,
|
|
453
|
+
includeInputSnapshot: true,
|
|
454
|
+
extractNarrixOutcome: true,
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const runtime = createExellixGraphRuntime({
|
|
459
|
+
graphLoader,
|
|
460
|
+
engineFactory,
|
|
461
|
+
tasksClient,
|
|
462
|
+
eventEmitter,
|
|
463
|
+
});
|
|
432
464
|
|
|
433
|
-
|
|
434
|
-
|
|
465
|
+
const result = await runtime.executeGraph({
|
|
466
|
+
model: graph,
|
|
467
|
+
runtime: {
|
|
468
|
+
jobId: 'job-123',
|
|
469
|
+
job: { agentId: 'agent-1', jobType: 'analysis' },
|
|
470
|
+
input: entryInput,
|
|
471
|
+
aliasConfig: { /* … */ },
|
|
472
|
+
runtimeObjects: buildExellixGraphRuntimeObjects({ graphActivixClient: activixClient }),
|
|
473
|
+
},
|
|
474
|
+
});
|
|
435
475
|
|
|
436
|
-
|
|
476
|
+
// Playground / debug UI — no direct Mongo:
|
|
477
|
+
const activities = await activixClient.getJobActivities({
|
|
478
|
+
jobId: result.jobId,
|
|
479
|
+
graphId: result.graphId,
|
|
480
|
+
limit: 500,
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Exports:** `createActivixFromEnv`, `resolveActivixExellixCollectionNamesFromEnv`, `createActivixExellixIntegration`, `createActivixGraphRunIntegration`, `createActivixNodeActivityIntegration`, `createActivixQueryableClient`, `ensureActivixInitialized`, `ensureActivixClientOnRuntimeObjects`, `buildGraphRunActivixRunContext`, `buildNodeActivixRunContext`.
|
|
485
|
+
|
|
486
|
+
### Collection tracking state (Activix 8.4+)
|
|
487
|
+
|
|
488
|
+
Legend rows in **`activix-collections`** may set **`state: 'track' | 'off'`**.
|
|
489
|
+
|
|
490
|
+
| Value | Meaning |
|
|
491
|
+
|-------|---------|
|
|
492
|
+
| **`track`** (default) | Mongo persistence for that collection |
|
|
493
|
+
| **`off`** | Same APIs; Activix skips Mongo (ephemeral in-process rows only) |
|
|
494
|
+
|
|
495
|
+
**Always** call `startRecord` / `completeRecord` / `failRecord` from integrations — never skip Activix in graph-engine when `off`. Toggle at runtime: `ax.setCollectionTrackingState(collectionName, 'off' | 'track')`. After external DB edits: `ax.refreshCollectionTrackingStates()`.
|
|
496
|
+
|
|
497
|
+
`createActivixFromEnv()` registers both exellix streams with **`runContext`** indexes and **`collectionRegistry.owner`** = `@exellix/graph-engine`. Collection names default to **`exellix-graph-runs`** and **`exellix-node-activity`** (override with **`ACTIVIX_GRAPH_RUNS_COLLECTION`** / **`ACTIVIX_NODE_ACTIVITY_COLLECTION`**).
|
|
498
|
+
|
|
499
|
+
### Record shape (graph run)
|
|
500
|
+
|
|
501
|
+
When using `createActivixGraphRunIntegration()` / `createActivixExellixIntegration()`:
|
|
502
|
+
|
|
503
|
+
- **Top-level `runContext`** on `startRecord` (not only nested inside custom fields).
|
|
504
|
+
- **Canonical response** at `outer.output.response` — only the graph’s **`finalOutput`**.
|
|
505
|
+
- **Diagnostics** under `outer.output.data` (nodes, execution, jobMemory, errors, …).
|
|
506
|
+
- **Top-level `metadata`** on the row for orchestrator observability (e.g. `graphNodeCount`, `inputVariableKeys`); **`outer.metadata`** carries **`kind`** / **`type`** (`exellix-graph-run`, `graph-run`).
|
|
437
507
|
|
|
438
508
|
### Graph start — bounded input summaries (Activix)
|
|
439
509
|
|
|
@@ -448,6 +518,19 @@ Correlation fields (`jobId`, `graphId`, `agentId`, `jobType`, `inputVariableKeys
|
|
|
448
518
|
|
|
449
519
|
**Not suitable to rely on for Activix persistence at graph start:** functions, class instances, streams, Buffers, live clients (HTTP/DB), circular graphs, or very large nested payloads — they are summarized or typed (e.g. `shape: "function"`, `shape: "instance"`) and never passed through to `startRecord` as raw references. For large memory, use `includeMemorySnapshots: true` only when you explicitly accept storing `outer.memory.start` / `end`; that remains opt-in and separate from `outer.input`.
|
|
450
520
|
|
|
521
|
+
## Logxer integration (runtime logs)
|
|
522
|
+
|
|
523
|
+
Graph-engine uses **`@x12i/logxer`** (4.6+) for structured logs and in-process **`getJobLogs`** (playground Logger, diagnostics).
|
|
524
|
+
|
|
525
|
+
- **Per-run logger:** Each `executeGraph` creates a run-scoped Logxer (`createGraphEngineLogxer({ logging })`) and binds it for the duration of the run.
|
|
526
|
+
- **Stack pass-through:** Pass **`logging?: StackLoggingOptions`** on `createExellixGraphRuntime` and/or per `executeGraph` to control downstream packages (`GRAPH_ENGINE`, `AI_TASKS`, …). The run is wrapped in **`runWithAiTasksStackLogging`** from `@exellix/ai-tasks`.
|
|
527
|
+
- **Service filter (Logger UI):** Top-level **`runtimeIdentity.service`** identifies the component that emitted the line. Graph-engine native events use **`graph-engine`**. Proxied downstream records keep the **origin** service (e.g. `ai-skills`, `@exellix/ai-tasks`) with wrapper attribution in **`proxyRuntimeIdentity`** — do not rely on **`data.runtimeIdentity.service`** for filtering.
|
|
528
|
+
- **Env:** `GRAPH_ENGINE_LOGS_LEVEL` (canonical); bulk stack levels via **`LOGXER_PACKAGE_LEVELS`** (see `@x12i/logxer` docs).
|
|
529
|
+
|
|
530
|
+
**Exports:** `createGraphEngineLogxer`, `getGraphEngineLogxer`, `createGraphEngineLogxerClient`, `ensureGraphEngineLogxerOnRuntimeObjects`, `runGraphWithLogContext`, `GRAPH_ENGINE_RUNTIME_SERVICE`, `normalizeGraphEngineLogMeta`.
|
|
531
|
+
|
|
532
|
+
Wire query surface on **`runtime.runtimeObjects.logxerClient`** (same pattern as Activix — see `buildExellixGraphRuntimeObjects` in testkit).
|
|
533
|
+
|
|
451
534
|
### `runtime.executeNode(input)`
|
|
452
535
|
|
|
453
536
|
Execute a single node — useful for tests and for stepping through a node in the context of an existing graph run. Pass `node`, `job`, optional `graph` / `execution`, and (when continuing a parent run) `graphRunTaskId` from the parent `ExecuteGraphResult.taskId` so `runTask` correlation, Activix records, and `runLog` lines stay aligned.
|
|
@@ -826,6 +909,18 @@ To execute a graph, supply a `graphLoader` that resolves `graphId` to JSON, buil
|
|
|
826
909
|
|
|
827
910
|
**`taskConfiguration.aiTasksOutputValidation`** on task nodes is forwarded as **`outputValidation`** on the `runTask` request (**`@exellix/ai-tasks` v7+**). Root **`outputConstraints`** is not part of the closed schema.
|
|
828
911
|
|
|
912
|
+
## Runtime observability (`runtimeObjects`)
|
|
913
|
+
|
|
914
|
+
Hosts and playgrounds compose a single **`runtimeObjects`** tree instead of querying Mongo or Logxer stores directly:
|
|
915
|
+
|
|
916
|
+
| Client | Source | Query API |
|
|
917
|
+
|--------|--------|-----------|
|
|
918
|
+
| **`activixClient`** | Your `Activix` instance via `createActivixQueryableClient` / `createActivixExellixIntegration` | `getJobActivities({ jobId, graphId?, nodeId?, limit? })` |
|
|
919
|
+
| **`logxerClient`** | Per-run graph-engine Logxer via `ensureGraphEngineLogxerOnRuntimeObjects` | `getJobLogs({ jobId, graphId?, nodeId?, level?, … })` |
|
|
920
|
+
| **`packagesRuntimeObjects`** | Optional subtree from `@exellix/ai-tasks` | Package-owned clients when exported |
|
|
921
|
+
|
|
922
|
+
Use **`buildExellixGraphRuntimeObjects({ graphActivixClient, graphLogxerClient, aiTasksRuntimeObjects })`** (testkit) and pass the result on **`runtime.runtimeObjects`**. **`setRuntimeObjectsLastJobId`** is applied automatically during `executeGraph`.
|
|
923
|
+
|
|
829
924
|
## Integration with Other Packages
|
|
830
925
|
|
|
831
926
|
See `.reports/` directory for request documents:
|
package/dist/src/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type { NodeExecutionResult, NodeTraceEntry, StepAttemptRecord, StepFailur
|
|
|
23
23
|
export type { RunLogEntry, RunLogLevel, RunLogScope, RunLogMode, RunLogBuildOptions, RunLogBuildResult, } from './types/runLog.js';
|
|
24
24
|
export { AI_TASKS_RUN_LOG_METADATA_KEY, AI_TASKS_LOGXER_RUN_ID_METADATA_KEY, DEFAULT_MAX_RUN_LOG_ENTRIES, DEFAULT_MAX_RUN_LOG_DATA_JSON_CHARS, } from './types/runLog.js';
|
|
25
25
|
export { buildRunLog, resolveRunLogLimits, truncateRunLogData, parseRunLogEntryTs, normalizeExternalRunLogEntries, extractTaskRunLogFromMetadata, extractLogxerCorrelationFromMetadata, } from './runtime/buildRunLog.js';
|
|
26
|
-
export { GRAPH_ENGINE_LOGXER_ENV_PREFIX, createGraphEngineLogxer, getGraphEngineLogxer, createGraphEngineLogxerClient, ensureGraphEngineLogxerOnRuntimeObjects, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, runGraphWithLogContext, patchGraphNodeLogContext, traceExecutionMemory, logGraphEngineErrorCode, DebugLogAbstract as GraphEngineDebugLogAbstract, fieldEvidence as graphEngineFieldEvidence, exceptionEvidence as graphEngineExceptionEvidence, } from './runtime/graphEngineLogxer.js';
|
|
26
|
+
export { GRAPH_ENGINE_LOGXER_ENV_PREFIX, createGraphEngineLogxer, getGraphEngineLogxer, createGraphEngineLogxerClient, ensureGraphEngineLogxerOnRuntimeObjects, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, runGraphWithLogContext, patchGraphNodeLogContext, traceExecutionMemory, logGraphEngineErrorCode, DebugLogAbstract as GraphEngineDebugLogAbstract, fieldEvidence as graphEngineFieldEvidence, exceptionEvidence as graphEngineExceptionEvidence, GRAPH_ENGINE_RUNTIME_SERVICE, GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY, extractOriginRuntimeIdentity, normalizeGraphEngineLogMeta, } from './runtime/graphEngineLogxer.js';
|
|
27
27
|
export type { GetJobLogsInput as GraphEngineGetJobLogsInput, GetJobLogsResult as GraphEngineGetJobLogsResult, LogRuntimeContext as GraphEngineLogRuntimeContext, StackLoggingOptions as GraphEngineStackLoggingOptions, } from './runtime/graphEngineLogxer.js';
|
|
28
28
|
export type { GraphExecutionEvent, NodeExecutionEvent, } from './types/events.js';
|
|
29
29
|
export { ExellixGraphError } from './errors/ExellixGraphError.js';
|
|
@@ -99,6 +99,8 @@ export type { CreateActivixGraphRunIntegrationOptions } from './integrations/Act
|
|
|
99
99
|
export { createActivixFromEnv, resolveActivixExellixCollectionNamesFromEnv, } from './integrations/createActivixFromEnv.js';
|
|
100
100
|
export { createActivixExellixIntegration } from './integrations/createActivixExellixIntegration.js';
|
|
101
101
|
export type { CreateActivixExellixIntegrationOptions } from './integrations/createActivixExellixIntegration.js';
|
|
102
|
+
export { createActivixQueryableClient, ensureActivixInitialized, buildGraphRunActivixRunContext, buildNodeActivixRunContext, } from './integrations/activixExellixShared.js';
|
|
103
|
+
export { ensureActivixClientOnRuntimeObjects } from './integrations/ensureActivixOnRuntimeObjects.js';
|
|
102
104
|
export { validateGraphPlanningCatalogDescriptorsInCatalox } from './integrations/cataloxGraphCatalog.js';
|
|
103
105
|
export type { GraphCatalogValidationIssue } from './integrations/cataloxGraphCatalog.js';
|
|
104
106
|
export { composeEventEmitters } from './runtime/events.js';
|
package/dist/src/index.js
CHANGED
|
@@ -16,7 +16,7 @@ export { mergeGraphDocumentModel, EXELLIX_GRAPH_MODEL_VARIABLE_KEY, EXELLIX_STRU
|
|
|
16
16
|
export { getTaskConfiguration } from './types/taskNodeConfiguration.js';
|
|
17
17
|
export { AI_TASKS_RUN_LOG_METADATA_KEY, AI_TASKS_LOGXER_RUN_ID_METADATA_KEY, DEFAULT_MAX_RUN_LOG_ENTRIES, DEFAULT_MAX_RUN_LOG_DATA_JSON_CHARS, } from './types/runLog.js';
|
|
18
18
|
export { buildRunLog, resolveRunLogLimits, truncateRunLogData, parseRunLogEntryTs, normalizeExternalRunLogEntries, extractTaskRunLogFromMetadata, extractLogxerCorrelationFromMetadata, } from './runtime/buildRunLog.js';
|
|
19
|
-
export { GRAPH_ENGINE_LOGXER_ENV_PREFIX, createGraphEngineLogxer, getGraphEngineLogxer, createGraphEngineLogxerClient, ensureGraphEngineLogxerOnRuntimeObjects, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, runGraphWithLogContext, patchGraphNodeLogContext, traceExecutionMemory, logGraphEngineErrorCode, DebugLogAbstract as GraphEngineDebugLogAbstract, fieldEvidence as graphEngineFieldEvidence, exceptionEvidence as graphEngineExceptionEvidence, } from './runtime/graphEngineLogxer.js';
|
|
19
|
+
export { GRAPH_ENGINE_LOGXER_ENV_PREFIX, createGraphEngineLogxer, getGraphEngineLogxer, createGraphEngineLogxerClient, ensureGraphEngineLogxerOnRuntimeObjects, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, runGraphWithLogContext, patchGraphNodeLogContext, traceExecutionMemory, logGraphEngineErrorCode, DebugLogAbstract as GraphEngineDebugLogAbstract, fieldEvidence as graphEngineFieldEvidence, exceptionEvidence as graphEngineExceptionEvidence, GRAPH_ENGINE_RUNTIME_SERVICE, GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY, extractOriginRuntimeIdentity, normalizeGraphEngineLogMeta, } from './runtime/graphEngineLogxer.js';
|
|
20
20
|
// Errors
|
|
21
21
|
export { ExellixGraphError } from './errors/ExellixGraphError.js';
|
|
22
22
|
export { ExellixGraphErrorCode } from './errors/exellixGraphErrorCodes.js';
|
|
@@ -74,6 +74,8 @@ export { createActivixNodeActivityIntegration } from './integrations/ActivixNode
|
|
|
74
74
|
export { createActivixGraphRunIntegration } from './integrations/ActivixGraphRunIntegration.js';
|
|
75
75
|
export { createActivixFromEnv, resolveActivixExellixCollectionNamesFromEnv, } from './integrations/createActivixFromEnv.js';
|
|
76
76
|
export { createActivixExellixIntegration } from './integrations/createActivixExellixIntegration.js';
|
|
77
|
+
export { createActivixQueryableClient, ensureActivixInitialized, buildGraphRunActivixRunContext, buildNodeActivixRunContext, } from './integrations/activixExellixShared.js';
|
|
78
|
+
export { ensureActivixClientOnRuntimeObjects } from './integrations/ensureActivixOnRuntimeObjects.js';
|
|
77
79
|
export { validateGraphPlanningCatalogDescriptorsInCatalox } from './integrations/cataloxGraphCatalog.js';
|
|
78
80
|
export { composeEventEmitters } from './runtime/events.js';
|
|
79
81
|
// Playground (full-visibility MD report)
|
|
@@ -23,8 +23,9 @@ export interface CreateActivixGraphRunIntegrationOptions {
|
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Returns an EventEmitter that persists graph lifecycle rows via Activix.
|
|
26
|
-
* Correlates start → complete/fail via
|
|
27
|
-
*
|
|
26
|
+
* Correlates start → complete/fail via in-process `activityId` (returned from `startRecord`).
|
|
27
|
+
* Activix 8.4+ owns collection tracking state (`track` / `off` on legend rows); always call
|
|
28
|
+
* `startRecord` / `completeRecord` / `failRecord` — persistence is decided inside Activix.
|
|
28
29
|
*
|
|
29
30
|
* On `graph:start`, `outer.input` contains only bounded **`inputSummary`** / **`requestSummary`**
|
|
30
31
|
* (JSON-serializable); raw event input/request objects are not copied to Activix.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildGraphRunActivixRunContext, ensureActivixInitialized, } from './activixExellixShared.js';
|
|
1
2
|
function summarizeValueForRecord(value) {
|
|
2
3
|
if (value === null || value === undefined) {
|
|
3
4
|
return { shape: 'empty' };
|
|
@@ -167,8 +168,9 @@ function summarizeForActivix(value, depth = 0, seen = new WeakSet()) {
|
|
|
167
168
|
}
|
|
168
169
|
/**
|
|
169
170
|
* Returns an EventEmitter that persists graph lifecycle rows via Activix.
|
|
170
|
-
* Correlates start → complete/fail via
|
|
171
|
-
*
|
|
171
|
+
* Correlates start → complete/fail via in-process `activityId` (returned from `startRecord`).
|
|
172
|
+
* Activix 8.4+ owns collection tracking state (`track` / `off` on legend rows); always call
|
|
173
|
+
* `startRecord` / `completeRecord` / `failRecord` — persistence is decided inside Activix.
|
|
172
174
|
*
|
|
173
175
|
* On `graph:start`, `outer.input` contains only bounded **`inputSummary`** / **`requestSummary`**
|
|
174
176
|
* (JSON-serializable); raw event input/request objects are not copied to Activix.
|
|
@@ -179,22 +181,12 @@ export function createActivixGraphRunIntegration(ax, options) {
|
|
|
179
181
|
const includeMemorySnapshots = options?.includeMemorySnapshots === true;
|
|
180
182
|
const colOpts = collection ? { collection } : undefined;
|
|
181
183
|
const graphRecordIds = new Map();
|
|
182
|
-
let initPromise = null;
|
|
183
|
-
function ensureInit() {
|
|
184
|
-
if (!initPromise) {
|
|
185
|
-
initPromise = ax.init().catch((err) => {
|
|
186
|
-
initPromise = null;
|
|
187
|
-
throw err;
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
return initPromise;
|
|
191
|
-
}
|
|
192
184
|
const eventEmitter = {
|
|
193
185
|
emit(event) {
|
|
194
186
|
setImmediate(async () => {
|
|
195
187
|
try {
|
|
196
188
|
if (event.type === 'graph:start') {
|
|
197
|
-
await
|
|
189
|
+
await ensureActivixInitialized(ax);
|
|
198
190
|
const graphEvent = event;
|
|
199
191
|
const data = graphEvent.data;
|
|
200
192
|
const key = `${graphEvent.jobId}:${graphEvent.graphId}:${graphEvent.taskId}`;
|
|
@@ -203,56 +195,49 @@ export function createActivixGraphRunIntegration(ax, options) {
|
|
|
203
195
|
const agentId = data?.agentId;
|
|
204
196
|
const jobType = data?.jobType;
|
|
205
197
|
const graphNodeCount = getGraphNodeCount(data?.graphDefinition);
|
|
206
|
-
|
|
207
|
-
// This SDK does not have a separate session id today, so we align it to `jobId`.
|
|
208
|
-
const runContext = {
|
|
209
|
-
sessionId: graphEvent.jobId,
|
|
198
|
+
const runContext = buildGraphRunActivixRunContext({
|
|
210
199
|
jobId: graphEvent.jobId,
|
|
211
200
|
taskId: graphEvent.taskId,
|
|
212
201
|
graphId: graphEvent.graphId,
|
|
213
202
|
agentId,
|
|
214
|
-
|
|
215
|
-
};
|
|
203
|
+
jobType,
|
|
204
|
+
});
|
|
216
205
|
const outerMemoryStart = data?.memoryStart;
|
|
217
206
|
const outerMetadata = {
|
|
218
207
|
kind: 'exellix-graph-run',
|
|
208
|
+
type: 'graph-run',
|
|
219
209
|
jobId: graphEvent.jobId,
|
|
220
210
|
taskId: graphEvent.taskId,
|
|
221
211
|
graphId: graphEvent.graphId,
|
|
222
|
-
agentId,
|
|
212
|
+
...(agentId != null ? { agentId } : {}),
|
|
223
213
|
...(jobType != null ? { jobType } : {}),
|
|
224
214
|
graphNodeCount,
|
|
225
215
|
inputVariableKeys,
|
|
226
216
|
eventTimestamp: graphEvent.timestamp,
|
|
227
217
|
};
|
|
228
|
-
const
|
|
229
|
-
kind: 'exellix-graph-run',
|
|
230
|
-
jobId: graphEvent.jobId,
|
|
231
|
-
taskId: graphEvent.taskId,
|
|
232
|
-
graphId: graphEvent.graphId,
|
|
233
|
-
agentId,
|
|
234
|
-
...(jobType != null ? { jobType } : {}),
|
|
235
|
-
graphNodeCount,
|
|
236
|
-
inputVariableKeys,
|
|
237
|
-
eventTimestamp: graphEvent.timestamp,
|
|
218
|
+
const { activityId } = await ax.startRecord({
|
|
238
219
|
runContext,
|
|
239
220
|
outer: {
|
|
240
221
|
input: {
|
|
241
222
|
inputSummary: summarizeForActivix(data?.input),
|
|
242
223
|
requestSummary: summarizeForActivix(data?.request),
|
|
243
224
|
},
|
|
244
|
-
output:
|
|
245
|
-
memory: {
|
|
246
|
-
...(includeMemorySnapshots ? { start: outerMemoryStart } : {}),
|
|
247
|
-
},
|
|
225
|
+
output: null,
|
|
248
226
|
metadata: outerMetadata,
|
|
227
|
+
...(includeMemorySnapshots && outerMemoryStart != null
|
|
228
|
+
? { memory: { start: outerMemoryStart } }
|
|
229
|
+
: {}),
|
|
249
230
|
},
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
231
|
+
metadata: {
|
|
232
|
+
graphNodeCount,
|
|
233
|
+
inputVariableKeys,
|
|
234
|
+
eventTimestamp: graphEvent.timestamp,
|
|
235
|
+
},
|
|
236
|
+
}, colOpts);
|
|
237
|
+
graphRecordIds.set(key, activityId);
|
|
253
238
|
}
|
|
254
239
|
else if (event.type === 'graph:complete') {
|
|
255
|
-
await
|
|
240
|
+
await ensureActivixInitialized(ax);
|
|
256
241
|
const graphEvent = event;
|
|
257
242
|
const key = `${graphEvent.jobId}:${graphEvent.graphId}:${graphEvent.taskId}`;
|
|
258
243
|
const recordId = graphRecordIds.get(key);
|
|
@@ -291,7 +276,7 @@ export function createActivixGraphRunIntegration(ax, options) {
|
|
|
291
276
|
graphRecordIds.delete(key);
|
|
292
277
|
}
|
|
293
278
|
else if (event.type === 'graph:fail') {
|
|
294
|
-
await
|
|
279
|
+
await ensureActivixInitialized(ax);
|
|
295
280
|
const graphEvent = event;
|
|
296
281
|
const key = `${graphEvent.jobId}:${graphEvent.graphId}:${graphEvent.taskId}`;
|
|
297
282
|
const recordId = graphRecordIds.get(key);
|
|
@@ -21,7 +21,8 @@ export interface CreateActivixNodeActivityIntegrationOptions {
|
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Returns an EventEmitter that persists node lifecycle rows via Activix.
|
|
24
|
-
* Correlates start → complete/fail
|
|
24
|
+
* Correlates start → complete/fail via in-process `activityId` from `startRecord`.
|
|
25
|
+
* Activix 8.4+ owns collection tracking state; always call lifecycle APIs (see `activixExellixShared`).
|
|
25
26
|
*/
|
|
26
27
|
export declare function createActivixNodeActivityIntegration(ax: Activix, options?: CreateActivixNodeActivityIntegrationOptions): {
|
|
27
28
|
eventEmitter: EventEmitter;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Listens for `node:start`, `node:complete`, and `node:fail` only. Graph-level events are ignored.
|
|
5
5
|
*/
|
|
6
|
+
import { buildNodeActivixRunContext, ensureActivixInitialized, } from './activixExellixShared.js';
|
|
6
7
|
function summarizeValueForRecord(value) {
|
|
7
8
|
if (value === null || value === undefined) {
|
|
8
9
|
return { shape: 'empty' };
|
|
@@ -24,7 +25,8 @@ function isPlainObject(v) {
|
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* Returns an EventEmitter that persists node lifecycle rows via Activix.
|
|
27
|
-
* Correlates start → complete/fail
|
|
28
|
+
* Correlates start → complete/fail via in-process `activityId` from `startRecord`.
|
|
29
|
+
* Activix 8.4+ owns collection tracking state; always call lifecycle APIs (see `activixExellixShared`).
|
|
28
30
|
*/
|
|
29
31
|
export function createActivixNodeActivityIntegration(ax, options) {
|
|
30
32
|
const collection = options?.collection;
|
|
@@ -32,16 +34,6 @@ export function createActivixNodeActivityIntegration(ax, options) {
|
|
|
32
34
|
const extractNarrixOutcome = options?.extractNarrixOutcome === true;
|
|
33
35
|
const colOpts = collection ? { collection } : undefined;
|
|
34
36
|
const nodeRecordIds = new Map();
|
|
35
|
-
let initPromise = null;
|
|
36
|
-
function ensureInit() {
|
|
37
|
-
if (!initPromise) {
|
|
38
|
-
initPromise = ax.init().catch((err) => {
|
|
39
|
-
initPromise = null;
|
|
40
|
-
throw err;
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
return initPromise;
|
|
44
|
-
}
|
|
45
37
|
const eventEmitter = {
|
|
46
38
|
emit(event) {
|
|
47
39
|
setImmediate(async () => {
|
|
@@ -52,22 +44,20 @@ export function createActivixNodeActivityIntegration(ax, options) {
|
|
|
52
44
|
const jobType = nodeEvent.data != null && typeof nodeEvent.data === 'object' && 'jobType' in nodeEvent.data
|
|
53
45
|
? nodeEvent.data.jobType
|
|
54
46
|
: undefined;
|
|
55
|
-
|
|
56
|
-
// This SDK does not have a separate session id today, so we align it to `jobId`.
|
|
57
|
-
const runContext = {
|
|
58
|
-
sessionId: nodeEvent.jobId,
|
|
47
|
+
const runContext = buildNodeActivixRunContext({
|
|
59
48
|
jobId: nodeEvent.jobId,
|
|
60
49
|
taskId: nodeEvent.taskId,
|
|
61
50
|
graphId: nodeEvent.graphId,
|
|
62
51
|
nodeId: nodeEvent.nodeId,
|
|
63
52
|
skillKey: nodeEvent.skillKey,
|
|
64
|
-
|
|
65
|
-
};
|
|
53
|
+
jobType,
|
|
54
|
+
});
|
|
66
55
|
const outerInput = isPlainObject(input) ? input : {};
|
|
67
56
|
const outerRequest = nodeEvent.data?.input?.request;
|
|
68
57
|
const outerMemoryStart = nodeEvent.data?.input?.memoryStart;
|
|
69
58
|
const outerMetadata = {
|
|
70
59
|
kind: 'exellix-graph-node',
|
|
60
|
+
type: 'task',
|
|
71
61
|
jobId: nodeEvent.jobId,
|
|
72
62
|
taskId: nodeEvent.taskId,
|
|
73
63
|
graphId: nodeEvent.graphId,
|
|
@@ -76,52 +66,42 @@ export function createActivixNodeActivityIntegration(ax, options) {
|
|
|
76
66
|
...(jobType != null ? { jobType } : {}),
|
|
77
67
|
eventTimestamp: nodeEvent.timestamp,
|
|
78
68
|
};
|
|
79
|
-
const
|
|
80
|
-
kind: 'exellix-graph-node',
|
|
81
|
-
jobId: nodeEvent.jobId,
|
|
82
|
-
taskId: nodeEvent.taskId,
|
|
83
|
-
graphId: nodeEvent.graphId,
|
|
84
|
-
nodeId: nodeEvent.nodeId,
|
|
85
|
-
skillKey: nodeEvent.skillKey,
|
|
86
|
-
...(jobType != null ? { jobType } : {}),
|
|
69
|
+
const topMetadata = {
|
|
87
70
|
eventTimestamp: nodeEvent.timestamp,
|
|
88
|
-
runContext,
|
|
89
|
-
outer: {
|
|
90
|
-
input: {
|
|
91
|
-
...outerInput,
|
|
92
|
-
request: outerRequest,
|
|
93
|
-
},
|
|
94
|
-
output: undefined,
|
|
95
|
-
memory: {
|
|
96
|
-
start: outerMemoryStart,
|
|
97
|
-
},
|
|
98
|
-
metadata: outerMetadata,
|
|
99
|
-
},
|
|
100
71
|
};
|
|
101
72
|
if (includeInputSnapshot && input && typeof input === 'object') {
|
|
102
73
|
const vars = input.variables;
|
|
103
74
|
if (vars && typeof vars === 'object') {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
75
|
+
const inputVariableKeys = Object.keys(vars);
|
|
76
|
+
outerMetadata.inputVariableKeys = inputVariableKeys;
|
|
77
|
+
topMetadata.inputVariableKeys = inputVariableKeys;
|
|
108
78
|
}
|
|
109
79
|
const jm = input.jobMemory;
|
|
110
80
|
const ex = jm?.execution;
|
|
111
81
|
if (ex != null && typeof ex === 'object') {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
82
|
+
const executionKeys = Object.keys(ex);
|
|
83
|
+
outerMetadata.executionKeys = executionKeys;
|
|
84
|
+
topMetadata.executionKeys = executionKeys;
|
|
116
85
|
}
|
|
117
86
|
}
|
|
87
|
+
const startPayload = {
|
|
88
|
+
runContext,
|
|
89
|
+
outer: {
|
|
90
|
+
input: {
|
|
91
|
+
...outerInput,
|
|
92
|
+
...(outerRequest !== undefined ? { request: outerRequest } : {}),
|
|
93
|
+
},
|
|
94
|
+
output: null,
|
|
95
|
+
metadata: outerMetadata,
|
|
96
|
+
...(outerMemoryStart !== undefined ? { memory: { start: outerMemoryStart } } : {}),
|
|
97
|
+
},
|
|
98
|
+
metadata: topMetadata,
|
|
99
|
+
};
|
|
118
100
|
const key = `${nodeEvent.graphId}:${nodeEvent.nodeId}:${nodeEvent.taskId}`;
|
|
119
|
-
// Start the record insert immediately (promise inserted into the map synchronously),
|
|
120
|
-
// but defer actual DB work until `ax.init()` is ready.
|
|
121
101
|
const recordPromise = (async () => {
|
|
122
|
-
await
|
|
123
|
-
const {
|
|
124
|
-
return
|
|
102
|
+
await ensureActivixInitialized(ax);
|
|
103
|
+
const { activityId } = await ax.startRecord(startPayload, colOpts);
|
|
104
|
+
return activityId;
|
|
125
105
|
})();
|
|
126
106
|
nodeRecordIds.set(key, recordPromise);
|
|
127
107
|
await recordPromise;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Activix, ActivixRunContext } from '@x12i/activix';
|
|
2
|
+
import type { ActivixQueryableClient } from '../runtime/runtimeObjects.js';
|
|
3
|
+
/** Recommended Mongo indexes for exellix-graph Activix streams (see `@x12i/activix` README). */
|
|
4
|
+
export declare const ACTIVIX_EXELLIX_RUN_CONTEXT_INDEXES: readonly [{
|
|
5
|
+
readonly keys: {
|
|
6
|
+
readonly 'runContext.jobId': 1;
|
|
7
|
+
};
|
|
8
|
+
}, {
|
|
9
|
+
readonly keys: {
|
|
10
|
+
readonly 'runContext.graphId': 1;
|
|
11
|
+
};
|
|
12
|
+
}, {
|
|
13
|
+
readonly keys: {
|
|
14
|
+
readonly 'runContext.taskId': 1;
|
|
15
|
+
};
|
|
16
|
+
}];
|
|
17
|
+
export declare const ACTIVIX_EXELLIX_NODE_RUN_CONTEXT_INDEXES: readonly [{
|
|
18
|
+
readonly keys: {
|
|
19
|
+
readonly 'runContext.jobId': 1;
|
|
20
|
+
};
|
|
21
|
+
}, {
|
|
22
|
+
readonly keys: {
|
|
23
|
+
readonly 'runContext.graphId': 1;
|
|
24
|
+
};
|
|
25
|
+
}, {
|
|
26
|
+
readonly keys: {
|
|
27
|
+
readonly 'runContext.taskId': 1;
|
|
28
|
+
};
|
|
29
|
+
}, {
|
|
30
|
+
readonly keys: {
|
|
31
|
+
readonly 'runContext.nodeId': 1;
|
|
32
|
+
};
|
|
33
|
+
}];
|
|
34
|
+
/**
|
|
35
|
+
* Single `init()` per Activix instance. Integrators always call Activix lifecycle APIs;
|
|
36
|
+
* collection `state` (track/off) is resolved inside Activix — do not branch in graph-engine.
|
|
37
|
+
*/
|
|
38
|
+
export declare function ensureActivixInitialized(ax: Activix): Promise<void>;
|
|
39
|
+
/** Official query surface: delegate to `Activix.getJobActivities` (8.x). */
|
|
40
|
+
export declare function createActivixQueryableClient(ax: Activix): ActivixQueryableClient;
|
|
41
|
+
export declare function buildGraphRunActivixRunContext(args: {
|
|
42
|
+
jobId: string;
|
|
43
|
+
taskId: string;
|
|
44
|
+
graphId: string;
|
|
45
|
+
agentId?: string;
|
|
46
|
+
jobType?: string;
|
|
47
|
+
}): ActivixRunContext;
|
|
48
|
+
export declare function buildNodeActivixRunContext(args: {
|
|
49
|
+
jobId: string;
|
|
50
|
+
taskId: string;
|
|
51
|
+
graphId: string;
|
|
52
|
+
nodeId: string;
|
|
53
|
+
skillKey?: string;
|
|
54
|
+
jobType?: string;
|
|
55
|
+
}): ActivixRunContext;
|
|
56
|
+
export declare function activixExellixCollectionRegistryOwner(): {
|
|
57
|
+
package: "@exellix/graph-engine";
|
|
58
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME } from '../runtime/runtimeObjects.js';
|
|
2
|
+
/** Recommended Mongo indexes for exellix-graph Activix streams (see `@x12i/activix` README). */
|
|
3
|
+
export const ACTIVIX_EXELLIX_RUN_CONTEXT_INDEXES = [
|
|
4
|
+
{ keys: { 'runContext.jobId': 1 } },
|
|
5
|
+
{ keys: { 'runContext.graphId': 1 } },
|
|
6
|
+
{ keys: { 'runContext.taskId': 1 } },
|
|
7
|
+
];
|
|
8
|
+
export const ACTIVIX_EXELLIX_NODE_RUN_CONTEXT_INDEXES = [
|
|
9
|
+
...ACTIVIX_EXELLIX_RUN_CONTEXT_INDEXES,
|
|
10
|
+
{ keys: { 'runContext.nodeId': 1 } },
|
|
11
|
+
];
|
|
12
|
+
let sharedInitByActivix = new WeakMap();
|
|
13
|
+
/**
|
|
14
|
+
* Single `init()` per Activix instance. Integrators always call Activix lifecycle APIs;
|
|
15
|
+
* collection `state` (track/off) is resolved inside Activix — do not branch in graph-engine.
|
|
16
|
+
*/
|
|
17
|
+
export function ensureActivixInitialized(ax) {
|
|
18
|
+
let p = sharedInitByActivix.get(ax);
|
|
19
|
+
if (!p) {
|
|
20
|
+
p = ax.init().catch((err) => {
|
|
21
|
+
sharedInitByActivix.delete(ax);
|
|
22
|
+
throw err;
|
|
23
|
+
});
|
|
24
|
+
sharedInitByActivix.set(ax, p);
|
|
25
|
+
}
|
|
26
|
+
return p;
|
|
27
|
+
}
|
|
28
|
+
/** Official query surface: delegate to `Activix.getJobActivities` (8.x). */
|
|
29
|
+
export function createActivixQueryableClient(ax) {
|
|
30
|
+
return {
|
|
31
|
+
getJobActivities(input) {
|
|
32
|
+
return ax.getJobActivities(input);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function buildGraphRunActivixRunContext(args) {
|
|
37
|
+
return {
|
|
38
|
+
sessionId: args.jobId,
|
|
39
|
+
jobId: args.jobId,
|
|
40
|
+
taskId: args.taskId,
|
|
41
|
+
graphId: args.graphId,
|
|
42
|
+
...(args.agentId != null && args.agentId !== '' ? { agentId: args.agentId } : {}),
|
|
43
|
+
...(args.jobType != null ? { jobType: args.jobType } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function buildNodeActivixRunContext(args) {
|
|
47
|
+
return {
|
|
48
|
+
sessionId: args.jobId,
|
|
49
|
+
jobId: args.jobId,
|
|
50
|
+
taskId: args.taskId,
|
|
51
|
+
graphId: args.graphId,
|
|
52
|
+
nodeId: args.nodeId,
|
|
53
|
+
...(args.skillKey != null && args.skillKey !== '' ? { skillKey: args.skillKey } : {}),
|
|
54
|
+
...(args.jobType != null ? { jobType: args.jobType } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function activixExellixCollectionRegistryOwner() {
|
|
58
|
+
return { package: EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME };
|
|
59
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Activix } from '@x12i/activix';
|
|
2
2
|
import type { EventEmitter } from '../runtime/events.js';
|
|
3
|
+
import type { ActivixQueryableClient } from '../runtime/runtimeObjects.js';
|
|
3
4
|
import { type CreateActivixNodeActivityIntegrationOptions } from './ActivixNodeActivityIntegration.js';
|
|
4
5
|
import { type CreateActivixGraphRunIntegrationOptions } from './ActivixGraphRunIntegration.js';
|
|
5
6
|
export interface CreateActivixExellixIntegrationOptions {
|
|
@@ -11,4 +12,6 @@ export interface CreateActivixExellixIntegrationOptions {
|
|
|
11
12
|
*/
|
|
12
13
|
export declare function createActivixExellixIntegration(ax: Activix, options?: CreateActivixExellixIntegrationOptions): {
|
|
13
14
|
eventEmitter: EventEmitter | undefined;
|
|
15
|
+
/** Use with {@link buildExellixGraphRuntimeObjects} as `graphActivixClient`. */
|
|
16
|
+
activixClient: ActivixQueryableClient;
|
|
14
17
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { composeEventEmitters } from '../runtime/events.js';
|
|
2
|
+
import { createActivixQueryableClient } from './activixExellixShared.js';
|
|
2
3
|
import { createActivixNodeActivityIntegration, } from './ActivixNodeActivityIntegration.js';
|
|
3
4
|
import { createActivixGraphRunIntegration, } from './ActivixGraphRunIntegration.js';
|
|
4
5
|
/**
|
|
@@ -12,5 +13,5 @@ export function createActivixExellixIntegration(ax, options) {
|
|
|
12
13
|
? createActivixGraphRunIntegration(ax, options.activixGraphRun)
|
|
13
14
|
: undefined;
|
|
14
15
|
const eventEmitter = composeEventEmitters(node?.eventEmitter, graph?.eventEmitter);
|
|
15
|
-
return { eventEmitter };
|
|
16
|
+
return { eventEmitter, activixClient: createActivixQueryableClient(ax) };
|
|
16
17
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Activix } from '@x12i/activix';
|
|
2
|
+
import { ACTIVIX_EXELLIX_NODE_RUN_CONTEXT_INDEXES, ACTIVIX_EXELLIX_RUN_CONTEXT_INDEXES, activixExellixCollectionRegistryOwner, } from './activixExellixShared.js';
|
|
2
3
|
function requiredEnv(name, strict) {
|
|
3
4
|
const v = process.env[name];
|
|
4
5
|
if (v && v.trim().length > 0)
|
|
@@ -45,9 +46,18 @@ export function createActivixFromEnv(options) {
|
|
|
45
46
|
return new Activix({
|
|
46
47
|
mongoUri,
|
|
47
48
|
defaultCollection: nodeActivityCollection,
|
|
49
|
+
collectionRegistry: {
|
|
50
|
+
owner: activixExellixCollectionRegistryOwner(),
|
|
51
|
+
},
|
|
48
52
|
collections: [
|
|
49
|
-
{
|
|
50
|
-
|
|
53
|
+
{
|
|
54
|
+
name: graphRunsCollection,
|
|
55
|
+
indexes: [...ACTIVIX_EXELLIX_RUN_CONTEXT_INDEXES],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: nodeActivityCollection,
|
|
59
|
+
indexes: [...ACTIVIX_EXELLIX_NODE_RUN_CONTEXT_INDEXES],
|
|
60
|
+
},
|
|
51
61
|
],
|
|
52
62
|
});
|
|
53
63
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Activix } from '@x12i/activix';
|
|
2
|
+
import type { RuntimeObjects } from '../runtime/runtimeObjects.js';
|
|
3
|
+
/** Wires graph-level `getJobActivities` when a host supplies an Activix instance on `runtimeObjects`. */
|
|
4
|
+
export declare function ensureActivixClientOnRuntimeObjects(runtimeObjects: RuntimeObjects | undefined, ax?: Activix): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createActivixQueryableClient } from './activixExellixShared.js';
|
|
2
|
+
/** Wires graph-level `getJobActivities` when a host supplies an Activix instance on `runtimeObjects`. */
|
|
3
|
+
export function ensureActivixClientOnRuntimeObjects(runtimeObjects, ax) {
|
|
4
|
+
if (!runtimeObjects || runtimeObjects.activixClient != null || ax == null)
|
|
5
|
+
return;
|
|
6
|
+
runtimeObjects.activixClient = createActivixQueryableClient(ax);
|
|
7
|
+
}
|
|
@@ -25,6 +25,7 @@ import { buildRunTaskIdentityEnvelope, mergeDefinedLlmCallParts, shouldForwardRu
|
|
|
25
25
|
import { buildRunLog, extractLogxerCorrelationFromMetadata, extractTaskRunLogFromMetadata, resolveRunLogLimits, } from "./buildRunLog.js";
|
|
26
26
|
import { setRuntimeObjectsLastJobId, summarizeRuntimeObjectsForPlayground } from "./runtimeObjects.js";
|
|
27
27
|
import { DebugLogAbstract, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, createGraphEngineLogxer, ensureGraphEngineLogxerOnRuntimeObjects, logGraphEngineErrorCode, patchGraphNodeLogContext, runGraphWithLogContext, traceExecutionMemory, } from "./graphEngineLogxer.js";
|
|
28
|
+
import { runWithAiTasksStackLogging } from "@exellix/ai-tasks";
|
|
28
29
|
import { assertHostJobId, newGraphRunTaskId } from "./graphRunIdentity.js";
|
|
29
30
|
import { resolveTaskKey } from "./resolveTaskKey.js";
|
|
30
31
|
import { buildPredicateEvalContextForNode, mirrorTaskVariablesOnExecution, readExecutionVariableBuckets, seedGraphVariableBucketsFromRuntime, } from "./variables.js";
|
|
@@ -1157,7 +1158,7 @@ export function createExellixGraphRuntime(opts) {
|
|
|
1157
1158
|
}
|
|
1158
1159
|
const resolvedGraphId = String(resolvedGraphIdRaw);
|
|
1159
1160
|
const runLogxer = createGraphEngineLogxer({ logging: merged.logging });
|
|
1160
|
-
return runGraphWithLogContext({ jobId, taskId: graphTaskId, graphId: resolvedGraphId, runId: graphTaskId }, async () => {
|
|
1161
|
+
return runWithAiTasksStackLogging(merged.logging, () => runGraphWithLogContext({ jobId, taskId: graphTaskId, graphId: resolvedGraphId, runId: graphTaskId }, async () => {
|
|
1161
1162
|
bindGraphEngineRunLogxer(runLogxer);
|
|
1162
1163
|
try {
|
|
1163
1164
|
assertCanonicalGraphDocument(graph, { jobId, graphId: resolvedGraphId });
|
|
@@ -1721,7 +1722,7 @@ export function createExellixGraphRuntime(opts) {
|
|
|
1721
1722
|
finally {
|
|
1722
1723
|
clearGraphEngineRunLogxer();
|
|
1723
1724
|
}
|
|
1724
|
-
});
|
|
1725
|
+
}));
|
|
1725
1726
|
}
|
|
1726
1727
|
return {
|
|
1727
1728
|
executeGraph,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LogMeta, RuntimeIdentity } from '@x12i/logxer';
|
|
2
|
+
/** Canonical filter key for graph-engine's own log lines. */
|
|
3
|
+
export declare const GRAPH_ENGINE_RUNTIME_SERVICE: "graph-engine";
|
|
4
|
+
/** Wrapper attribution when graph-engine proxies a downstream Logxer record. */
|
|
5
|
+
export declare const GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY: RuntimeIdentity;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the originating component identity from meta or nested payload shapes
|
|
8
|
+
* (e.g. proxied envelopes stored under `data.runtimeIdentity`).
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractOriginRuntimeIdentity(meta: LogMeta | undefined): RuntimeIdentity | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Ensures top-level `runtimeIdentity.service` is the log origin for filtering.
|
|
13
|
+
* Graph-engine-native lines use `graph-engine`; proxied downstream lines keep the
|
|
14
|
+
* downstream service and record wrapper attribution on `proxyRuntimeIdentity`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeGraphEngineLogMeta(meta?: LogMeta): LogMeta | undefined;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME } from './runtimeObjects.js';
|
|
2
|
+
/** Canonical filter key for graph-engine's own log lines. */
|
|
3
|
+
export const GRAPH_ENGINE_RUNTIME_SERVICE = 'graph-engine';
|
|
4
|
+
/** Wrapper attribution when graph-engine proxies a downstream Logxer record. */
|
|
5
|
+
export const GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY = {
|
|
6
|
+
service: GRAPH_ENGINE_RUNTIME_SERVICE,
|
|
7
|
+
libraryPackage: EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME,
|
|
8
|
+
};
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function readRuntimeIdentity(value) {
|
|
13
|
+
if (!isRecord(value))
|
|
14
|
+
return undefined;
|
|
15
|
+
const service = value.service;
|
|
16
|
+
if (typeof service !== 'string' || service.length === 0)
|
|
17
|
+
return undefined;
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function isDownstreamOrigin(identity) {
|
|
21
|
+
const service = identity.service;
|
|
22
|
+
return typeof service === 'string' && service.length > 0 && service !== GRAPH_ENGINE_RUNTIME_SERVICE;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the originating component identity from meta or nested payload shapes
|
|
26
|
+
* (e.g. proxied envelopes stored under `data.runtimeIdentity`).
|
|
27
|
+
*/
|
|
28
|
+
export function extractOriginRuntimeIdentity(meta) {
|
|
29
|
+
if (!meta)
|
|
30
|
+
return undefined;
|
|
31
|
+
const candidates = [];
|
|
32
|
+
if (meta.runtimeIdentity != null)
|
|
33
|
+
candidates.push(meta.runtimeIdentity);
|
|
34
|
+
const data = meta.data;
|
|
35
|
+
if (isRecord(data)) {
|
|
36
|
+
if (data.runtimeIdentity != null)
|
|
37
|
+
candidates.push(data.runtimeIdentity);
|
|
38
|
+
if (isRecord(data.data) && data.data.runtimeIdentity != null) {
|
|
39
|
+
candidates.push(data.data.runtimeIdentity);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const raw of candidates) {
|
|
43
|
+
const identity = readRuntimeIdentity(raw);
|
|
44
|
+
if (identity != null && isDownstreamOrigin(identity))
|
|
45
|
+
return identity;
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ensures top-level `runtimeIdentity.service` is the log origin for filtering.
|
|
51
|
+
* Graph-engine-native lines use `graph-engine`; proxied downstream lines keep the
|
|
52
|
+
* downstream service and record wrapper attribution on `proxyRuntimeIdentity`.
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeGraphEngineLogMeta(meta) {
|
|
55
|
+
if (meta == null)
|
|
56
|
+
return meta;
|
|
57
|
+
const origin = extractOriginRuntimeIdentity(meta);
|
|
58
|
+
if (origin != null) {
|
|
59
|
+
return {
|
|
60
|
+
...meta,
|
|
61
|
+
runtimeIdentity: origin,
|
|
62
|
+
proxyRuntimeIdentity: GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const existing = readRuntimeIdentity(meta.runtimeIdentity);
|
|
66
|
+
const runtimeIdentity = {
|
|
67
|
+
...GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY,
|
|
68
|
+
...(existing ?? {}),
|
|
69
|
+
service: GRAPH_ENGINE_RUNTIME_SERVICE,
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
...meta,
|
|
73
|
+
runtimeIdentity,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { GetJobLogsInput, GetJobLogsResult, Logxer, LogRuntimeContext, StackLoggingOptions } from '@x12i/logxer';
|
|
6
6
|
import type { LogxerQueryableClient, RuntimeObjects } from './runtimeObjects.js';
|
|
7
|
+
export { GRAPH_ENGINE_RUNTIME_SERVICE, GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY, extractOriginRuntimeIdentity, normalizeGraphEngineLogMeta, } from './graphEngineLogMeta.js';
|
|
7
8
|
/** Env prefix for package-level log level: `GRAPH_ENGINE_LOGS_LEVEL` (canonical). */
|
|
8
9
|
export declare const GRAPH_ENGINE_LOGXER_ENV_PREFIX: "GRAPH_ENGINE";
|
|
9
10
|
/** Factory for a graph-engine Logxer instance (logxer 4.5+ stack pass-through). */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const logxer = await import('@x12i/logxer');
|
|
2
2
|
import { ExellixGraphErrorCode } from '../errors/exellixGraphErrorCodes.js';
|
|
3
3
|
import { EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME } from './runtimeObjects.js';
|
|
4
|
+
import { normalizeGraphEngineLogMeta, } from './graphEngineLogMeta.js';
|
|
5
|
+
export { GRAPH_ENGINE_RUNTIME_SERVICE, GRAPH_ENGINE_PROXY_RUNTIME_IDENTITY, extractOriginRuntimeIdentity, normalizeGraphEngineLogMeta, } from './graphEngineLogMeta.js';
|
|
4
6
|
/** Env prefix for package-level log level: `GRAPH_ENGINE_LOGS_LEVEL` (canonical). */
|
|
5
7
|
export const GRAPH_ENGINE_LOGXER_ENV_PREFIX = 'GRAPH_ENGINE';
|
|
6
8
|
const GRAPH_ENGINE_DIAGNOSTIC_CATALOG = {
|
|
@@ -75,20 +77,50 @@ let defaultLogxer;
|
|
|
75
77
|
let activeRunLogxer;
|
|
76
78
|
function buildGraphEngineLogxerConfig(logging) {
|
|
77
79
|
return {
|
|
78
|
-
runtimeIdentity: { service: 'graph-engine' },
|
|
79
80
|
diagnostics: {
|
|
80
81
|
catalog: GRAPH_ENGINE_DIAGNOSTIC_CATALOG,
|
|
81
82
|
},
|
|
82
83
|
...(logging ? { stack: logging } : {}),
|
|
83
84
|
};
|
|
84
85
|
}
|
|
86
|
+
const GRAPH_ENGINE_LOG_METHODS = new Set([
|
|
87
|
+
'verbose',
|
|
88
|
+
'debug',
|
|
89
|
+
'info',
|
|
90
|
+
'warn',
|
|
91
|
+
'error',
|
|
92
|
+
'success',
|
|
93
|
+
'infoCode',
|
|
94
|
+
'warnCode',
|
|
95
|
+
'errorCode',
|
|
96
|
+
'errorFromCaught',
|
|
97
|
+
'diagnostic',
|
|
98
|
+
]);
|
|
99
|
+
/** Preserve downstream `runtimeIdentity.service` on proxied records; tag graph-engine wrapper separately. */
|
|
100
|
+
function wrapGraphEngineLogxer(inner) {
|
|
101
|
+
return new Proxy(inner, {
|
|
102
|
+
get(target, prop, receiver) {
|
|
103
|
+
const value = Reflect.get(target, prop, receiver);
|
|
104
|
+
if (typeof value !== 'function' || !GRAPH_ENGINE_LOG_METHODS.has(String(prop))) {
|
|
105
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
106
|
+
}
|
|
107
|
+
return (...args) => {
|
|
108
|
+
if (args.length >= 2 && args[1] != null) {
|
|
109
|
+
args[1] = normalizeGraphEngineLogMeta(args[1]);
|
|
110
|
+
}
|
|
111
|
+
return Reflect.apply(value, target, args);
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
85
116
|
/** Factory for a graph-engine Logxer instance (logxer 4.5+ stack pass-through). */
|
|
86
117
|
export function createGraphEngineLogxer(options) {
|
|
87
|
-
|
|
118
|
+
const inner = logxer.createLogxer({
|
|
88
119
|
packageName: EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME,
|
|
89
120
|
envPrefix: GRAPH_ENGINE_LOGXER_ENV_PREFIX,
|
|
90
121
|
debugNamespace: 'graph-engine',
|
|
91
122
|
}, buildGraphEngineLogxerConfig(options?.logging));
|
|
123
|
+
return wrapGraphEngineLogxer(inner);
|
|
92
124
|
}
|
|
93
125
|
/** Default process logger (env / host registry). Lazily created without stack overrides. */
|
|
94
126
|
export function getGraphEngineLogxer() {
|
|
@@ -127,11 +159,11 @@ export function traceExecutionMemory(scope, message, data) {
|
|
|
127
159
|
process.env.DEBUG_OUTPUT_MAPPING !== 'true') {
|
|
128
160
|
return;
|
|
129
161
|
}
|
|
130
|
-
getGraphEngineLogxer().verbose(message, {
|
|
162
|
+
getGraphEngineLogxer().verbose(message, normalizeGraphEngineLogMeta({
|
|
131
163
|
scope,
|
|
132
164
|
...data,
|
|
133
165
|
debugKind: logxer.DebugLogAbstract.STATE,
|
|
134
|
-
});
|
|
166
|
+
}));
|
|
135
167
|
}
|
|
136
168
|
export function logGraphEngineErrorCode(code, _message, ctx) {
|
|
137
169
|
const instance = getGraphEngineLogxer();
|
|
@@ -139,14 +171,14 @@ export function logGraphEngineErrorCode(code, _message, ctx) {
|
|
|
139
171
|
...(ctx.error != null ? [logxer.exceptionEvidence(ctx.error)] : []),
|
|
140
172
|
...Object.entries(ctx.evidence ?? {}).map(([path, value]) => logxer.fieldEvidence(path, value)),
|
|
141
173
|
];
|
|
142
|
-
instance.errorCode(code, {
|
|
174
|
+
instance.errorCode(code, normalizeGraphEngineLogMeta({
|
|
143
175
|
graphId: ctx.graphId,
|
|
144
176
|
nodeId: ctx.nodeId,
|
|
145
177
|
jobId: ctx.jobId,
|
|
146
178
|
taskId: ctx.taskId,
|
|
147
179
|
debugKind: logxer.DebugLogAbstract.ANOMALY,
|
|
148
180
|
...(evidence.length ? { evidence } : {}),
|
|
149
|
-
});
|
|
181
|
+
}));
|
|
150
182
|
}
|
|
151
183
|
export const DebugLogAbstract = logxer.DebugLogAbstract;
|
|
152
184
|
export const fieldEvidence = logxer.fieldEvidence;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exellix/graph-engine",
|
|
3
|
-
"version": "7.3.
|
|
3
|
+
"version": "7.3.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Graph executor SDK",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@exellix/ai-tasks": "^8.2.
|
|
54
|
-
"@x12i/activix": "8.
|
|
53
|
+
"@exellix/ai-tasks": "^8.2.3",
|
|
54
|
+
"@x12i/activix": "8.4.1",
|
|
55
55
|
"@x12i/ai-profiles": "1.7.2",
|
|
56
56
|
"@x12i/catalox": "5.1.3",
|
|
57
57
|
"@x12i/env": "4.0.1",
|
|
58
|
-
"@x12i/funcx": "4.2.
|
|
58
|
+
"@x12i/funcx": "4.2.8",
|
|
59
59
|
"@x12i/graphenix": "2.5.0",
|
|
60
60
|
"@x12i/graphenix-format": "2.0.0",
|
|
61
61
|
"@x12i/logxer": "^4.6.0",
|