@qloo/qloo-harness 0.1.18
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/LICENSE +21 -0
- package/README.md +394 -0
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/app.js +48 -0
- package/dist/bin.js +14 -0
- package/dist/build.js +117 -0
- package/dist/cli.js +95 -0
- package/dist/doctor.js +1019 -0
- package/dist/exec.js +782 -0
- package/dist/guided-journey.js +223 -0
- package/dist/index.d.ts +1321 -0
- package/dist/index.js +156 -0
- package/dist/integration-plan.js +1097 -0
- package/dist/mcp.js +909 -0
- package/dist/observability.js +115 -0
- package/dist/paths.js +77 -0
- package/dist/plan.js +163 -0
- package/dist/profiles.js +63 -0
- package/dist/project-context.js +364 -0
- package/dist/qloo-presentation.js +358 -0
- package/dist/qloo-tools.js +2195 -0
- package/dist/resolution-provider.js +1380 -0
- package/dist/router.js +6061 -0
- package/dist/runtime/explore-policy.js +666 -0
- package/dist/runtime/pi-adapter.js +259 -0
- package/dist/runtime/pi-command-policy.js +74 -0
- package/dist/runtime/qloo-header.js +173 -0
- package/dist/runtime/resources.js +37 -0
- package/dist/setup.js +1138 -0
- package/dist/update-manager.js +906 -0
- package/dist/workflow-executor.js +976 -0
- package/package.json +72 -0
- package/resources/BUILD.md +24 -0
- package/resources/EXPLORE.md +34 -0
- package/resources/INTEGRATE.md +28 -0
- package/resources/PLAN.md +23 -0
- package/resources/SYSTEM.md +49 -0
|
@@ -0,0 +1,976 @@
|
|
|
1
|
+
import { createRequire as __qlooCreateRequire } from "node:module";
|
|
2
|
+
const require = __qlooCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// packages/qloo-tool-schema/dist/upstream.lock.json
|
|
5
|
+
var upstream_lock_default = {
|
|
6
|
+
lockVersion: 1,
|
|
7
|
+
source: {
|
|
8
|
+
documentationUrl: "https://docs.qloo.com",
|
|
9
|
+
registryUrl: "https://dash.readme.com/api/v1/api-registry/4svkj1svmrti5tfx",
|
|
10
|
+
registryId: "4svkj1svmrti5tfx",
|
|
11
|
+
retrievedAt: "2026-08-20",
|
|
12
|
+
apiTitle: "Qloo API",
|
|
13
|
+
apiVersion: "2.0",
|
|
14
|
+
openapiVersion: "3.1.0",
|
|
15
|
+
sha256: "da8d4b830f2a646815d25afcaa653f81f1ad939707e2e2560d2d0b9f103076f1"
|
|
16
|
+
},
|
|
17
|
+
expectations: {
|
|
18
|
+
productionServer: "https://api.qloo.com",
|
|
19
|
+
authentication: {
|
|
20
|
+
scheme: "ApiKey",
|
|
21
|
+
type: "apiKey",
|
|
22
|
+
location: "header",
|
|
23
|
+
header: "X-Api-Key"
|
|
24
|
+
},
|
|
25
|
+
getPaths: [
|
|
26
|
+
"/",
|
|
27
|
+
"/entities",
|
|
28
|
+
"/search",
|
|
29
|
+
"/v2/analysis/compare",
|
|
30
|
+
"/v2/audiences",
|
|
31
|
+
"/v2/audiences/types",
|
|
32
|
+
"/v2/insights",
|
|
33
|
+
"/v2/tags",
|
|
34
|
+
"/v2/tags/types",
|
|
35
|
+
"/v2/trending"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
documentedExceptions: [
|
|
39
|
+
{
|
|
40
|
+
value: "urn:demographics",
|
|
41
|
+
scope: "/v2/insights filter.type",
|
|
42
|
+
status: "documented-but-not-enumerated",
|
|
43
|
+
documentationUrl: "https://docs.qloo.com/reference/demographics-use-case",
|
|
44
|
+
treatment: "Preserve as an explicit documentation exception; do not synthesize an endpoint payload schema from it."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: "urn:tag",
|
|
48
|
+
scope: "/v2/insights filter.type",
|
|
49
|
+
status: "documented-but-not-enumerated",
|
|
50
|
+
documentationUrl: "https://docs.qloo.com/reference/taste-analysis",
|
|
51
|
+
treatment: "The pinned specification mentions this value in diversify.by documentation but omits it from the filter.type enum; preserve the discrepancy for review."
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// packages/qloo-tool-schema/dist/src/catalog.js
|
|
57
|
+
var QLOO_TOOL_CATALOG_VERSION = "1.0.0";
|
|
58
|
+
var QLOO_TOOL_RESULT_SCHEMA_VERSION = "1.0-preview.1";
|
|
59
|
+
var QLOO_WORKFLOW_OPERATION_IDS = [
|
|
60
|
+
"recommend",
|
|
61
|
+
"rank",
|
|
62
|
+
"describe",
|
|
63
|
+
"where_popular",
|
|
64
|
+
"compare_audiences",
|
|
65
|
+
"entity_tags",
|
|
66
|
+
"audience_demographics",
|
|
67
|
+
"trends",
|
|
68
|
+
"find_tags"
|
|
69
|
+
];
|
|
70
|
+
var QLOO_CAPABILITIES_TOOL_NAME = "qloo_capabilities";
|
|
71
|
+
var QLOO_INSIGHTS_ENTITY_TYPES = [
|
|
72
|
+
{ id: "artist", urn: "urn:entity:artist" },
|
|
73
|
+
{ id: "book", urn: "urn:entity:book" },
|
|
74
|
+
{ id: "brand", urn: "urn:entity:brand" },
|
|
75
|
+
{ id: "movie", urn: "urn:entity:movie" },
|
|
76
|
+
{ id: "person", urn: "urn:entity:person" },
|
|
77
|
+
{ id: "place", urn: "urn:entity:place" },
|
|
78
|
+
{ id: "podcast", urn: "urn:entity:podcast" },
|
|
79
|
+
{ id: "tv_show", urn: "urn:entity:tv_show" },
|
|
80
|
+
{ id: "videogame", urn: "urn:entity:videogame" }
|
|
81
|
+
];
|
|
82
|
+
var QLOO_SEARCH_ENTITY_TYPES = [
|
|
83
|
+
...QLOO_INSIGHTS_ENTITY_TYPES,
|
|
84
|
+
{ id: "locality", urn: "urn:entity:locality" },
|
|
85
|
+
{ id: "actor", urn: "urn:entity:actor" },
|
|
86
|
+
{ id: "album", urn: "urn:entity:album" },
|
|
87
|
+
{ id: "author", urn: "urn:entity:author" },
|
|
88
|
+
{ id: "director", urn: "urn:entity:director" }
|
|
89
|
+
];
|
|
90
|
+
function buildEntityTypeAliases(entityTypes) {
|
|
91
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
92
|
+
const urnById = new Map(entityTypes.map(({ id, urn }) => [id, urn]));
|
|
93
|
+
for (const entityType of entityTypes) {
|
|
94
|
+
aliases.set(entityType.id, entityType.urn);
|
|
95
|
+
aliases.set(entityType.urn, entityType.urn);
|
|
96
|
+
aliases.set(`${entityType.id}s`, entityType.urn);
|
|
97
|
+
}
|
|
98
|
+
const addAlias = (alias, id) => {
|
|
99
|
+
const urn = urnById.get(id);
|
|
100
|
+
if (urn)
|
|
101
|
+
aliases.set(alias, urn);
|
|
102
|
+
};
|
|
103
|
+
addAlias("people", "person");
|
|
104
|
+
addAlias("localities", "locality");
|
|
105
|
+
addAlias("tv", "tv_show");
|
|
106
|
+
addAlias("show", "tv_show");
|
|
107
|
+
addAlias("shows", "tv_show");
|
|
108
|
+
addAlias("tv show", "tv_show");
|
|
109
|
+
addAlias("tv shows", "tv_show");
|
|
110
|
+
addAlias("game", "videogame");
|
|
111
|
+
addAlias("games", "videogame");
|
|
112
|
+
addAlias("video game", "videogame");
|
|
113
|
+
addAlias("video games", "videogame");
|
|
114
|
+
return aliases;
|
|
115
|
+
}
|
|
116
|
+
var insightsEntityTypeByAlias = buildEntityTypeAliases(QLOO_INSIGHTS_ENTITY_TYPES);
|
|
117
|
+
var searchEntityTypeByAlias = buildEntityTypeAliases(QLOO_SEARCH_ENTITY_TYPES);
|
|
118
|
+
var operationSummaries = {
|
|
119
|
+
recommend: "Find entities for a taste profile, audience, or collection of signals.",
|
|
120
|
+
rank: "Rank a supplied set of options for signals, location, or audience.",
|
|
121
|
+
describe: "Resolve and describe one Qloo entity.",
|
|
122
|
+
where_popular: "Find geographic areas where an entity has comparatively strong affinity.",
|
|
123
|
+
compare_audiences: "Contrast two signal groups and identify shared or differentiating affinities.",
|
|
124
|
+
entity_tags: "Retrieve concepts and tags that characterize entities.",
|
|
125
|
+
audience_demographics: "Retrieve aggregate audience segments associated with an entity.",
|
|
126
|
+
trends: "Retrieve interest or trend information over a time range.",
|
|
127
|
+
find_tags: "Search the Qloo tag ontology by natural-language concept."
|
|
128
|
+
};
|
|
129
|
+
var QLOO_WORKFLOW_OPERATIONS = Object.freeze(QLOO_WORKFLOW_OPERATION_IDS.map((id) => Object.freeze({
|
|
130
|
+
id,
|
|
131
|
+
toolName: `qloo_${id}`,
|
|
132
|
+
summary: operationSummaries[id],
|
|
133
|
+
since: QLOO_TOOL_CATALOG_VERSION
|
|
134
|
+
})));
|
|
135
|
+
var upstreamLock = upstream_lock_default;
|
|
136
|
+
var upstreamGetPaths = Object.freeze([
|
|
137
|
+
...upstreamLock.expectations.getPaths
|
|
138
|
+
]);
|
|
139
|
+
var documentedExceptions = Object.freeze(upstreamLock.documentedExceptions.map((exception) => Object.freeze({ ...exception })));
|
|
140
|
+
var QLOO_CAPABILITIES_TOOL = Object.freeze({
|
|
141
|
+
name: QLOO_CAPABILITIES_TOOL_NAME,
|
|
142
|
+
description: "Return the versioned Qloo workflow catalog and pinned upstream API contract metadata without making a network request.",
|
|
143
|
+
inputSchema: Object.freeze({
|
|
144
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
145
|
+
type: "object",
|
|
146
|
+
additionalProperties: false,
|
|
147
|
+
properties: Object.freeze({
|
|
148
|
+
operation_ids: Object.freeze({
|
|
149
|
+
type: "array",
|
|
150
|
+
description: "Optional canonical operation IDs to include. Omit for the complete catalog.",
|
|
151
|
+
uniqueItems: true,
|
|
152
|
+
items: Object.freeze({
|
|
153
|
+
type: "string",
|
|
154
|
+
enum: QLOO_WORKFLOW_OPERATION_IDS
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
var operationIds = new Set(QLOO_WORKFLOW_OPERATION_IDS);
|
|
161
|
+
|
|
162
|
+
// packages/qloo-tool-schema/dist/src/workflow-contracts.js
|
|
163
|
+
import { Type } from "typebox";
|
|
164
|
+
import { Value } from "typebox/value";
|
|
165
|
+
var QLOO_TOOL_DEFAULT_LIMIT = 10;
|
|
166
|
+
var QLOO_TOOL_MAX_RESULTS = 20;
|
|
167
|
+
var QLOO_TAG_BOOLEAN_OPERATORS = ["union", "intersection"];
|
|
168
|
+
var insightsEntityTypeIds = QLOO_INSIGHTS_ENTITY_TYPES.map(({ id }) => id);
|
|
169
|
+
var searchEntityTypeIds = QLOO_SEARCH_ENTITY_TYPES.map(({ id }) => id);
|
|
170
|
+
var QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA = Type.String({
|
|
171
|
+
enum: insightsEntityTypeIds,
|
|
172
|
+
description: `Qloo Insights entity type: ${insightsEntityTypeIds.join(", ")}.`
|
|
173
|
+
});
|
|
174
|
+
var QLOO_SEARCH_ENTITY_TYPE_SCHEMA = Type.String({
|
|
175
|
+
enum: searchEntityTypeIds,
|
|
176
|
+
description: `Qloo search entity type: ${searchEntityTypeIds.join(", ")}.`
|
|
177
|
+
});
|
|
178
|
+
var QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA = Type.String({
|
|
179
|
+
enum: QLOO_TAG_BOOLEAN_OPERATORS,
|
|
180
|
+
description: "Combine tag values with union (any) or intersection (all)."
|
|
181
|
+
});
|
|
182
|
+
var QLOO_LIMIT_SCHEMA = Type.Optional(Type.Integer({
|
|
183
|
+
minimum: 1,
|
|
184
|
+
maximum: QLOO_TOOL_MAX_RESULTS,
|
|
185
|
+
default: QLOO_TOOL_DEFAULT_LIMIT,
|
|
186
|
+
description: `Maximum results to return (1-${QLOO_TOOL_MAX_RESULTS}).`
|
|
187
|
+
}));
|
|
188
|
+
var QLOO_ENTITY_INPUTS_SCHEMA = Type.Array(Type.String({ minLength: 1 }), {
|
|
189
|
+
minItems: 1,
|
|
190
|
+
maxItems: 10,
|
|
191
|
+
description: "Entity names or Qloo entity UUIDs. Keep one combined taste profile in one call."
|
|
192
|
+
});
|
|
193
|
+
var QLOO_TAG_INPUTS_SCHEMA = Type.Array(Type.String({ minLength: 1 }), {
|
|
194
|
+
minItems: 1,
|
|
195
|
+
maxItems: 10,
|
|
196
|
+
description: "Natural-language tag concepts or stable Qloo tag URNs."
|
|
197
|
+
});
|
|
198
|
+
var QLOO_DEMOGRAPHIC_SCHEMA = Type.String({
|
|
199
|
+
minLength: 1,
|
|
200
|
+
description: "Audience demographic in natural language, such as 'young women', 'men 25-34', or 'millennials'. It is converted to documented Qloo demographic signals.",
|
|
201
|
+
examples: ["young women", "men 25-34", "millennials"]
|
|
202
|
+
});
|
|
203
|
+
var QLOO_REQUEST_PREVIEW_SCHEMA = Type.Object({
|
|
204
|
+
method: Type.Literal("GET"),
|
|
205
|
+
path: Type.String({ minLength: 1 }),
|
|
206
|
+
query: Type.Unknown()
|
|
207
|
+
}, { additionalProperties: false });
|
|
208
|
+
var QLOO_RESULT_ENVELOPE_SCHEMA = Type.Object({
|
|
209
|
+
schema_version: Type.Literal(QLOO_TOOL_RESULT_SCHEMA_VERSION),
|
|
210
|
+
operation: Type.String(),
|
|
211
|
+
status: Type.Union([
|
|
212
|
+
Type.Literal("ok"),
|
|
213
|
+
Type.Literal("empty"),
|
|
214
|
+
Type.Literal("needs_input"),
|
|
215
|
+
Type.Literal("partial"),
|
|
216
|
+
Type.Literal("degraded"),
|
|
217
|
+
Type.Literal("error")
|
|
218
|
+
]),
|
|
219
|
+
summary: Type.Optional(Type.String()),
|
|
220
|
+
interpretation: Type.Optional(Type.Unknown()),
|
|
221
|
+
results: Type.Optional(Type.Unknown()),
|
|
222
|
+
result_count: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
223
|
+
warnings: Type.Optional(Type.Array(Type.String())),
|
|
224
|
+
query_intent: Type.Optional(Type.Unknown()),
|
|
225
|
+
error: Type.Optional(Type.Object({
|
|
226
|
+
code: Type.String(),
|
|
227
|
+
layer: Type.String(),
|
|
228
|
+
retryable: Type.Boolean(),
|
|
229
|
+
recovery: Type.String()
|
|
230
|
+
}, { additionalProperties: false })),
|
|
231
|
+
execution: Type.Object({
|
|
232
|
+
transport: Type.String({ enum: ["direct", "cli", "mcp"] }),
|
|
233
|
+
transport_name: Type.String(),
|
|
234
|
+
correlation_id: Type.String(),
|
|
235
|
+
duration_ms: Type.Number({ minimum: 0 })
|
|
236
|
+
}, { additionalProperties: false }),
|
|
237
|
+
provenance: Type.Optional(Type.Object({
|
|
238
|
+
source: Type.String(),
|
|
239
|
+
endpoint: Type.String(),
|
|
240
|
+
documentation: Type.String(),
|
|
241
|
+
transport: Type.Optional(Type.String()),
|
|
242
|
+
requests: Type.Optional(Type.Array(QLOO_REQUEST_PREVIEW_SCHEMA, {
|
|
243
|
+
maxItems: 20
|
|
244
|
+
}))
|
|
245
|
+
}, { additionalProperties: false }))
|
|
246
|
+
}, { additionalProperties: true });
|
|
247
|
+
var QLOO_WORKFLOW_INPUT_SCHEMAS = {
|
|
248
|
+
recommend: Type.Object({
|
|
249
|
+
target_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
|
|
250
|
+
signals: Type.Optional(QLOO_ENTITY_INPUTS_SCHEMA),
|
|
251
|
+
signal_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
|
|
252
|
+
signal_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
|
|
253
|
+
signal_location: Type.Optional(Type.String({ minLength: 1 })),
|
|
254
|
+
demographic: Type.Optional(QLOO_DEMOGRAPHIC_SCHEMA),
|
|
255
|
+
filter_location: Type.Optional(Type.String({ minLength: 1 })),
|
|
256
|
+
include_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
|
|
257
|
+
include_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
|
|
258
|
+
exclude_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
|
|
259
|
+
exclude_tags_operator: Type.Optional(QLOO_TAG_BOOLEAN_OPERATOR_SCHEMA),
|
|
260
|
+
explain: Type.Optional(Type.Boolean({ default: true })),
|
|
261
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
262
|
+
}, { additionalProperties: false }),
|
|
263
|
+
rank: Type.Object({
|
|
264
|
+
options: QLOO_ENTITY_INPUTS_SCHEMA,
|
|
265
|
+
option_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
|
|
266
|
+
signals: Type.Optional(QLOO_ENTITY_INPUTS_SCHEMA),
|
|
267
|
+
signal_location: Type.Optional(Type.String({ minLength: 1 })),
|
|
268
|
+
demographic: Type.Optional(QLOO_DEMOGRAPHIC_SCHEMA),
|
|
269
|
+
include_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA),
|
|
270
|
+
exclude_tags: Type.Optional(QLOO_TAG_INPUTS_SCHEMA)
|
|
271
|
+
}, { additionalProperties: false }),
|
|
272
|
+
describe: Type.Object({
|
|
273
|
+
entity: Type.String({ minLength: 1 }),
|
|
274
|
+
type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA)
|
|
275
|
+
}, { additionalProperties: false }),
|
|
276
|
+
where_popular: Type.Object({
|
|
277
|
+
entity: Type.String({ minLength: 1 }),
|
|
278
|
+
entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
|
|
279
|
+
within: Type.String({
|
|
280
|
+
minLength: 1,
|
|
281
|
+
description: "Required geographic area that constrains the heatmap."
|
|
282
|
+
}),
|
|
283
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
284
|
+
}, { additionalProperties: false }),
|
|
285
|
+
compare_audiences: Type.Object({
|
|
286
|
+
group_a: QLOO_ENTITY_INPUTS_SCHEMA,
|
|
287
|
+
group_b: QLOO_ENTITY_INPUTS_SCHEMA,
|
|
288
|
+
target_type: Type.Optional(QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA),
|
|
289
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
290
|
+
}, { additionalProperties: false }),
|
|
291
|
+
entity_tags: Type.Object({
|
|
292
|
+
entities: QLOO_ENTITY_INPUTS_SCHEMA,
|
|
293
|
+
entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
|
|
294
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
295
|
+
}, { additionalProperties: false }),
|
|
296
|
+
audience_demographics: Type.Object({
|
|
297
|
+
entity: Type.String({ minLength: 1 }),
|
|
298
|
+
entity_type: Type.Optional(QLOO_SEARCH_ENTITY_TYPE_SCHEMA),
|
|
299
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
300
|
+
}, { additionalProperties: false }),
|
|
301
|
+
trends: Type.Object({
|
|
302
|
+
entities: Type.Array(Type.String({ minLength: 1 }), { minItems: 1, maxItems: 5 }),
|
|
303
|
+
entity_type: QLOO_INSIGHTS_ENTITY_TYPE_SCHEMA,
|
|
304
|
+
start_date: Type.String({
|
|
305
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
306
|
+
description: "Inclusive start date in YYYY-MM-DD format."
|
|
307
|
+
}),
|
|
308
|
+
end_date: Type.String({
|
|
309
|
+
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
310
|
+
description: "Inclusive end date in YYYY-MM-DD format."
|
|
311
|
+
}),
|
|
312
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
313
|
+
}, { additionalProperties: false }),
|
|
314
|
+
find_tags: Type.Object({
|
|
315
|
+
query: Type.String({ minLength: 1 }),
|
|
316
|
+
semantic: Type.Optional(Type.Boolean({ default: true })),
|
|
317
|
+
limit: QLOO_LIMIT_SCHEMA
|
|
318
|
+
}, { additionalProperties: false })
|
|
319
|
+
};
|
|
320
|
+
var sharedWorkflowBehavior = Object.freeze({
|
|
321
|
+
readOnly: true,
|
|
322
|
+
idempotent: true,
|
|
323
|
+
mutating: false,
|
|
324
|
+
destructive: false,
|
|
325
|
+
openWorld: true,
|
|
326
|
+
concurrency: "safe_for_independent_inputs",
|
|
327
|
+
requiredCredential: "qloo_api",
|
|
328
|
+
defaultResultBudget: QLOO_TOOL_DEFAULT_LIMIT,
|
|
329
|
+
maximumResultBudget: QLOO_TOOL_MAX_RESULTS,
|
|
330
|
+
safeRetryClasses: Object.freeze(["dns", "connect", "timeout", "rate_limit", "upstream_5xx"]),
|
|
331
|
+
supportedTransports: Object.freeze(["direct", "mcp"])
|
|
332
|
+
});
|
|
333
|
+
var mediumLatencyOperations = /* @__PURE__ */ new Set([
|
|
334
|
+
"recommend",
|
|
335
|
+
"rank",
|
|
336
|
+
"compare_audiences",
|
|
337
|
+
"entity_tags",
|
|
338
|
+
"audience_demographics",
|
|
339
|
+
"trends"
|
|
340
|
+
]);
|
|
341
|
+
var QLOO_WORKFLOW_BEHAVIORS = Object.freeze(Object.fromEntries(Object.keys(QLOO_WORKFLOW_INPUT_SCHEMAS).map((operation) => [
|
|
342
|
+
operation,
|
|
343
|
+
Object.freeze({
|
|
344
|
+
...sharedWorkflowBehavior,
|
|
345
|
+
expectedLatency: mediumLatencyOperations.has(operation) ? "medium" : "low"
|
|
346
|
+
})
|
|
347
|
+
])));
|
|
348
|
+
var QLOO_WORKFLOW_METADATA = {
|
|
349
|
+
recommend: {
|
|
350
|
+
toolName: "qloo_recommend",
|
|
351
|
+
label: "Qloo recommendations",
|
|
352
|
+
description: "Find Qloo entities related to one combined entity, tag, location, and demographic taste profile. Signals influence affinity; filters constrain output.",
|
|
353
|
+
promptSnippet: "Recommend entities from a combined Qloo taste profile",
|
|
354
|
+
promptGuidelines: [
|
|
355
|
+
"Pass every related taste and audience signal together in one qloo_recommend call.",
|
|
356
|
+
"Use signal_location for audience location and filter_location to constrain result geography.",
|
|
357
|
+
"Include demographic and location in the same call when both describe the audience."
|
|
358
|
+
],
|
|
359
|
+
documentation: ["https://docs.qloo.com/reference/insights-api-deep-dive"]
|
|
360
|
+
},
|
|
361
|
+
rank: {
|
|
362
|
+
toolName: "qloo_rank",
|
|
363
|
+
label: "Qloo rank",
|
|
364
|
+
description: "Rank one supplied option set against one shared entity, location, demographic, and tag profile. Scores from separate calls are not comparable.",
|
|
365
|
+
promptSnippet: "Rank a caller-supplied shortlist with Qloo",
|
|
366
|
+
promptGuidelines: ["Pass every option in one qloo_rank call so scores remain comparable."],
|
|
367
|
+
documentation: ["https://docs.qloo.com/reference/insights-api-deep-dive"]
|
|
368
|
+
},
|
|
369
|
+
describe: {
|
|
370
|
+
toolName: "qloo_describe",
|
|
371
|
+
label: "Qloo entity",
|
|
372
|
+
description: "Resolve one named entity or Qloo UUID and return only metadata present in Qloo.",
|
|
373
|
+
promptSnippet: "Resolve and describe one Qloo entity",
|
|
374
|
+
documentation: ["https://docs.qloo.com/reference/get-search", "https://docs.qloo.com/reference/get-entities"]
|
|
375
|
+
},
|
|
376
|
+
where_popular: {
|
|
377
|
+
toolName: "qloo_where_popular",
|
|
378
|
+
label: "Qloo geographic affinity",
|
|
379
|
+
description: "Find geographic areas where one entity has strong query-relative affinity. This is distinct from filtering recommendations to a place.",
|
|
380
|
+
promptSnippet: "Find where an entity is comparatively popular",
|
|
381
|
+
documentation: ["https://docs.qloo.com/reference/heatmaps-use-case"]
|
|
382
|
+
},
|
|
383
|
+
compare_audiences: {
|
|
384
|
+
toolName: "qloo_compare_audiences",
|
|
385
|
+
label: "Qloo audience comparison",
|
|
386
|
+
description: "Compare two complete groups of entity signals in one Qloo analysis request.",
|
|
387
|
+
promptSnippet: "Compare two Qloo taste-signal groups",
|
|
388
|
+
documentation: ["https://docs.qloo.com/reference/analysis-compare"]
|
|
389
|
+
},
|
|
390
|
+
entity_tags: {
|
|
391
|
+
toolName: "qloo_entity_tags",
|
|
392
|
+
label: "Qloo entity tags",
|
|
393
|
+
description: "Retrieve Qloo concepts that jointly characterize one or more entities using the documented urn:tag Insights workflow.",
|
|
394
|
+
promptSnippet: "Find concepts that characterize Qloo entities",
|
|
395
|
+
documentation: ["https://docs.qloo.com/reference/taste-analysis"]
|
|
396
|
+
},
|
|
397
|
+
audience_demographics: {
|
|
398
|
+
toolName: "qloo_audience_demographics",
|
|
399
|
+
label: "Qloo audience demographics",
|
|
400
|
+
description: "Retrieve aggregate demographic distributions associated with one entity through the documented urn:demographics Insights workflow.",
|
|
401
|
+
promptSnippet: "Inspect aggregate demographics associated with a Qloo entity",
|
|
402
|
+
documentation: ["https://docs.qloo.com/reference/demographics-use-case"]
|
|
403
|
+
},
|
|
404
|
+
trends: {
|
|
405
|
+
toolName: "qloo_trends",
|
|
406
|
+
label: "Qloo trends",
|
|
407
|
+
description: "Retrieve Qloo time-series popularity metrics for one to five resolved entities over an ISO date range.",
|
|
408
|
+
promptSnippet: "Track Qloo entity popularity metrics over time",
|
|
409
|
+
documentation: ["https://docs.qloo.com/reference/get-trending"]
|
|
410
|
+
},
|
|
411
|
+
find_tags: {
|
|
412
|
+
toolName: "qloo_find_tags",
|
|
413
|
+
label: "Qloo tag search",
|
|
414
|
+
description: "Search Qloo's tag ontology by natural-language concept and return stable tag URNs.",
|
|
415
|
+
promptSnippet: "Search the Qloo tag ontology",
|
|
416
|
+
documentation: ["https://docs.qloo.com/reference/get-tags-1"]
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
var QLOO_WORKFLOW_CONTRACTS = Object.freeze(Object.fromEntries(Object.entries(QLOO_WORKFLOW_METADATA).map(([id, metadata]) => [
|
|
420
|
+
id,
|
|
421
|
+
Object.freeze({
|
|
422
|
+
id,
|
|
423
|
+
...metadata,
|
|
424
|
+
behavior: QLOO_WORKFLOW_BEHAVIORS[id],
|
|
425
|
+
inputSchema: QLOO_WORKFLOW_INPUT_SCHEMAS[id],
|
|
426
|
+
resultSchema: QLOO_RESULT_ENVELOPE_SCHEMA
|
|
427
|
+
})
|
|
428
|
+
])));
|
|
429
|
+
var QLOO_QUERY_INTENT_VERSION = "1.0-preview.1";
|
|
430
|
+
function createQlooQueryIntent(operation, input) {
|
|
431
|
+
const base = {
|
|
432
|
+
schema_version: QLOO_QUERY_INTENT_VERSION,
|
|
433
|
+
source_contract_version: QLOO_TOOL_CATALOG_VERSION,
|
|
434
|
+
operation,
|
|
435
|
+
job: operation,
|
|
436
|
+
signals: {},
|
|
437
|
+
filters: {},
|
|
438
|
+
operators: {},
|
|
439
|
+
output: {},
|
|
440
|
+
assumptions: [],
|
|
441
|
+
unresolved: []
|
|
442
|
+
};
|
|
443
|
+
switch (operation) {
|
|
444
|
+
case "recommend": {
|
|
445
|
+
const value = input;
|
|
446
|
+
return {
|
|
447
|
+
...base,
|
|
448
|
+
target: { type: value.target_type },
|
|
449
|
+
signals: {
|
|
450
|
+
...value.signals ? { entities: value.signals } : {},
|
|
451
|
+
...value.signal_tags ? { tags: value.signal_tags } : {},
|
|
452
|
+
...value.signal_location ? { location: value.signal_location } : {},
|
|
453
|
+
...value.demographic ? { demographic: value.demographic } : {}
|
|
454
|
+
},
|
|
455
|
+
filters: {
|
|
456
|
+
...value.include_tags ? { includeTags: value.include_tags } : {},
|
|
457
|
+
...value.exclude_tags ? { excludeTags: value.exclude_tags } : {},
|
|
458
|
+
...value.filter_location ? { location: value.filter_location } : {}
|
|
459
|
+
},
|
|
460
|
+
operators: {
|
|
461
|
+
...value.signal_tags ? { signalTags: value.signal_tags_operator ?? "intersection" } : {},
|
|
462
|
+
...value.include_tags ? { includeTags: value.include_tags_operator ?? "union" } : {},
|
|
463
|
+
...value.exclude_tags ? { excludeTags: value.exclude_tags_operator ?? "union" } : {}
|
|
464
|
+
},
|
|
465
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT, explain: value.explain ?? true },
|
|
466
|
+
assumptions: [
|
|
467
|
+
...value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : [],
|
|
468
|
+
...value.explain === void 0 ? ["explain=true"] : []
|
|
469
|
+
]
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
case "rank": {
|
|
473
|
+
const value = input;
|
|
474
|
+
return {
|
|
475
|
+
...base,
|
|
476
|
+
target: { type: value.option_type },
|
|
477
|
+
signals: {
|
|
478
|
+
...value.signals ? { entities: value.signals } : {},
|
|
479
|
+
...value.signal_location ? { location: value.signal_location } : {},
|
|
480
|
+
...value.demographic ? { demographic: value.demographic } : {}
|
|
481
|
+
},
|
|
482
|
+
filters: {
|
|
483
|
+
candidateEntities: value.options,
|
|
484
|
+
...value.include_tags ? { includeTags: value.include_tags } : {},
|
|
485
|
+
...value.exclude_tags ? { excludeTags: value.exclude_tags } : {}
|
|
486
|
+
},
|
|
487
|
+
operators: {
|
|
488
|
+
...value.include_tags ? { includeTags: "union" } : {},
|
|
489
|
+
...value.exclude_tags ? { excludeTags: "union" } : {}
|
|
490
|
+
},
|
|
491
|
+
output: { limit: value.options.length },
|
|
492
|
+
assumptions: []
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
case "describe": {
|
|
496
|
+
const value = input;
|
|
497
|
+
return { ...base, target: { ...value.type ? { type: value.type } : {}, entities: [value.entity] } };
|
|
498
|
+
}
|
|
499
|
+
case "where_popular": {
|
|
500
|
+
const value = input;
|
|
501
|
+
return {
|
|
502
|
+
...base,
|
|
503
|
+
target: { ...value.entity_type ? { type: value.entity_type } : {}, entities: [value.entity] },
|
|
504
|
+
filters: { location: value.within },
|
|
505
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
506
|
+
assumptions: value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
case "compare_audiences": {
|
|
510
|
+
const value = input;
|
|
511
|
+
return {
|
|
512
|
+
...base,
|
|
513
|
+
...value.target_type ? { target: { type: value.target_type } } : {},
|
|
514
|
+
signals: { groups: [value.group_a, value.group_b] },
|
|
515
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
516
|
+
assumptions: value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
case "entity_tags": {
|
|
520
|
+
const value = input;
|
|
521
|
+
return {
|
|
522
|
+
...base,
|
|
523
|
+
...value.entity_type ? { target: { type: value.entity_type } } : {},
|
|
524
|
+
signals: { entities: value.entities },
|
|
525
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
526
|
+
assumptions: value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
case "audience_demographics": {
|
|
530
|
+
const value = input;
|
|
531
|
+
return {
|
|
532
|
+
...base,
|
|
533
|
+
target: value.entity_type ? { type: value.entity_type, entities: [value.entity] } : { entities: [value.entity] },
|
|
534
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
535
|
+
assumptions: value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
case "trends": {
|
|
539
|
+
const value = input;
|
|
540
|
+
return {
|
|
541
|
+
...base,
|
|
542
|
+
target: { type: value.entity_type, entities: value.entities },
|
|
543
|
+
filters: { startDate: value.start_date, endDate: value.end_date },
|
|
544
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
545
|
+
assumptions: value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
case "find_tags": {
|
|
549
|
+
const value = input;
|
|
550
|
+
return {
|
|
551
|
+
...base,
|
|
552
|
+
target: { concept: value.query },
|
|
553
|
+
output: { limit: value.limit ?? QLOO_TOOL_DEFAULT_LIMIT },
|
|
554
|
+
assumptions: [
|
|
555
|
+
...value.semantic === void 0 ? ["semantic=true"] : [],
|
|
556
|
+
...value.limit === void 0 ? [`limit=${QLOO_TOOL_DEFAULT_LIMIT}`] : []
|
|
557
|
+
]
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function validationIssues(schema, value) {
|
|
563
|
+
return [...Value.Errors(schema, value)].slice(0, 20).map((issue) => ({
|
|
564
|
+
path: issue.keyword === "additionalProperties" && "additionalProperties" in issue.params && Array.isArray(issue.params.additionalProperties) && typeof issue.params.additionalProperties[0] === "string" ? `${issue.instancePath}/${issue.params.additionalProperties[0]}` : issue.instancePath || "/",
|
|
565
|
+
message: issue.message
|
|
566
|
+
}));
|
|
567
|
+
}
|
|
568
|
+
function validateQlooWorkflowInput(operation, value) {
|
|
569
|
+
const schema = QLOO_WORKFLOW_INPUT_SCHEMAS[operation];
|
|
570
|
+
if (Value.Check(schema, value)) {
|
|
571
|
+
return { ok: true, value };
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
ok: false,
|
|
575
|
+
issues: validationIssues(schema, value)
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function validateQlooWorkflowResult(value) {
|
|
579
|
+
if (Value.Check(QLOO_RESULT_ENVELOPE_SCHEMA, value)) {
|
|
580
|
+
return { ok: true, value };
|
|
581
|
+
}
|
|
582
|
+
return { ok: false, issues: validationIssues(QLOO_RESULT_ENVELOPE_SCHEMA, value) };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// packages/qloo-tool-schema/dist/src/resolution-contracts.js
|
|
586
|
+
import { Type as Type2 } from "typebox";
|
|
587
|
+
var QLOO_RESOLUTION_CONTRACT_VERSION = "1.0-preview.1";
|
|
588
|
+
var QLOO_RESOLUTION_PROVIDER_DESCRIPTOR_SCHEMA = Type2.Object({
|
|
589
|
+
contract_version: Type2.Literal(QLOO_RESOLUTION_CONTRACT_VERSION),
|
|
590
|
+
provider_id: Type2.String({ minLength: 1 }),
|
|
591
|
+
name: Type2.String({ minLength: 1 }),
|
|
592
|
+
entity_strategy: Type2.String({ minLength: 1 }),
|
|
593
|
+
tag_strategy: Type2.String({ minLength: 1 }),
|
|
594
|
+
remote: Type2.Boolean(),
|
|
595
|
+
uses_model: Type2.Boolean(),
|
|
596
|
+
fallback: Type2.Literal("none")
|
|
597
|
+
}, { additionalProperties: false });
|
|
598
|
+
var QLOO_RESOLUTION_CANDIDATE_SCHEMA = Type2.Object({
|
|
599
|
+
id: Type2.String({ minLength: 1 }),
|
|
600
|
+
name: Type2.String({ minLength: 1 }),
|
|
601
|
+
type: Type2.Optional(Type2.String({ minLength: 1 })),
|
|
602
|
+
rank: Type2.Optional(Type2.Integer({ minimum: 1 })),
|
|
603
|
+
score: Type2.Optional(Type2.Number()),
|
|
604
|
+
popularity: Type2.Optional(Type2.Number()),
|
|
605
|
+
parent_types: Type2.Optional(Type2.Array(Type2.String({ minLength: 1 }), {
|
|
606
|
+
maxItems: 20,
|
|
607
|
+
uniqueItems: true
|
|
608
|
+
})),
|
|
609
|
+
description: Type2.Optional(Type2.String({ minLength: 1, maxLength: 500 })),
|
|
610
|
+
release_year: Type2.Optional(Type2.Integer()),
|
|
611
|
+
address: Type2.Optional(Type2.Unknown())
|
|
612
|
+
}, { additionalProperties: false });
|
|
613
|
+
var QLOO_RESOLUTION_PROVENANCE_SCHEMA = Type2.Object({
|
|
614
|
+
contract_version: Type2.Literal(QLOO_RESOLUTION_CONTRACT_VERSION),
|
|
615
|
+
provider_id: Type2.String({ minLength: 1 }),
|
|
616
|
+
provider_name: Type2.String({ minLength: 1 }),
|
|
617
|
+
endpoint: Type2.String({ minLength: 1 }),
|
|
618
|
+
strategy: Type2.String({ minLength: 1 }),
|
|
619
|
+
remote: Type2.Boolean(),
|
|
620
|
+
uses_model: Type2.Boolean(),
|
|
621
|
+
provider_version: Type2.Optional(Type2.String({ minLength: 1 })),
|
|
622
|
+
cache_status: Type2.Optional(Type2.String({ minLength: 1 }))
|
|
623
|
+
}, { additionalProperties: false });
|
|
624
|
+
var QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA = {
|
|
625
|
+
input: Type2.String({ minLength: 1 }),
|
|
626
|
+
provenance: QLOO_RESOLUTION_PROVENANCE_SCHEMA,
|
|
627
|
+
warnings: Type2.Optional(Type2.Array(Type2.String()))
|
|
628
|
+
};
|
|
629
|
+
var QLOO_RESOLUTION_OUTCOME_SCHEMA = Type2.Union([
|
|
630
|
+
Type2.Object({
|
|
631
|
+
...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
|
|
632
|
+
status: Type2.Literal("resolved"),
|
|
633
|
+
match: Type2.Union([
|
|
634
|
+
Type2.Literal("identifier"),
|
|
635
|
+
Type2.Literal("exact"),
|
|
636
|
+
Type2.Literal("semantic")
|
|
637
|
+
]),
|
|
638
|
+
selected: QLOO_RESOLUTION_CANDIDATE_SCHEMA,
|
|
639
|
+
alternatives: Type2.Optional(Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA))
|
|
640
|
+
}, { additionalProperties: false }),
|
|
641
|
+
Type2.Object({
|
|
642
|
+
...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
|
|
643
|
+
status: Type2.Literal("ambiguous"),
|
|
644
|
+
candidates: Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA)
|
|
645
|
+
}, { additionalProperties: false }),
|
|
646
|
+
Type2.Object({
|
|
647
|
+
...QLOO_RESOLUTION_OUTCOME_COMMON_SCHEMA,
|
|
648
|
+
status: Type2.Literal("not_found"),
|
|
649
|
+
candidates: Type2.Optional(Type2.Array(QLOO_RESOLUTION_CANDIDATE_SCHEMA))
|
|
650
|
+
}, { additionalProperties: false })
|
|
651
|
+
]);
|
|
652
|
+
|
|
653
|
+
// packages/qloo-client-ts/dist/errors.js
|
|
654
|
+
var QlooClientError = class extends Error {
|
|
655
|
+
code;
|
|
656
|
+
retryable;
|
|
657
|
+
status;
|
|
658
|
+
requestId;
|
|
659
|
+
details;
|
|
660
|
+
constructor(code, message, options = {}) {
|
|
661
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
662
|
+
this.name = "QlooClientError";
|
|
663
|
+
this.code = code;
|
|
664
|
+
this.retryable = options.retryable ?? false;
|
|
665
|
+
if (options.status !== void 0)
|
|
666
|
+
this.status = options.status;
|
|
667
|
+
if (options.requestId !== void 0)
|
|
668
|
+
this.requestId = options.requestId;
|
|
669
|
+
if (options.details !== void 0)
|
|
670
|
+
this.details = options.details;
|
|
671
|
+
}
|
|
672
|
+
toJSON() {
|
|
673
|
+
return {
|
|
674
|
+
name: this.name,
|
|
675
|
+
code: this.code,
|
|
676
|
+
message: this.message,
|
|
677
|
+
retryable: this.retryable,
|
|
678
|
+
...this.status === void 0 ? {} : { status: this.status },
|
|
679
|
+
...this.requestId === void 0 ? {} : { requestId: this.requestId },
|
|
680
|
+
...this.details === void 0 ? {} : { details: this.details }
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// packages/qloo-client-ts/dist/client.js
|
|
686
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
687
|
+
|
|
688
|
+
// apps/qloo-harness/dist/workflow-executor.js
|
|
689
|
+
import { QlooResolutionProviderError } from "./resolution-provider.js";
|
|
690
|
+
var QlooWorkflowExecutionError = class extends Error {
|
|
691
|
+
operation;
|
|
692
|
+
transport;
|
|
693
|
+
code;
|
|
694
|
+
layer;
|
|
695
|
+
retryable;
|
|
696
|
+
expected;
|
|
697
|
+
recovery;
|
|
698
|
+
correlationId;
|
|
699
|
+
durationMs;
|
|
700
|
+
constructor(operation, transport, message, cause, metadata = {}) {
|
|
701
|
+
super(message, cause === void 0 ? void 0 : { cause });
|
|
702
|
+
this.name = "QlooWorkflowExecutionError";
|
|
703
|
+
this.operation = operation;
|
|
704
|
+
this.transport = transport;
|
|
705
|
+
this.code = metadata.code ?? "HARNESS_INTERNAL";
|
|
706
|
+
this.layer = metadata.layer ?? "harness";
|
|
707
|
+
this.retryable = metadata.retryable ?? false;
|
|
708
|
+
this.expected = metadata.expected ?? false;
|
|
709
|
+
this.recovery = metadata.recovery ?? "Run qloo doctor and inspect the local workflow trace before retrying.";
|
|
710
|
+
if (metadata.correlationId)
|
|
711
|
+
this.correlationId = metadata.correlationId;
|
|
712
|
+
if (metadata.durationMs !== void 0)
|
|
713
|
+
this.durationMs = metadata.durationMs;
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
function qlooClientErrorInChain(error) {
|
|
717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
718
|
+
let current = error;
|
|
719
|
+
for (let depth = 0; depth < 8 && current !== void 0 && !seen.has(current); depth += 1) {
|
|
720
|
+
if (current instanceof QlooClientError)
|
|
721
|
+
return current;
|
|
722
|
+
seen.add(current);
|
|
723
|
+
current = current !== null && typeof current === "object" ? Reflect.get(current, "cause") : void 0;
|
|
724
|
+
}
|
|
725
|
+
return void 0;
|
|
726
|
+
}
|
|
727
|
+
function resolutionProviderErrorInChain(error) {
|
|
728
|
+
const seen = /* @__PURE__ */ new Set();
|
|
729
|
+
let current = error;
|
|
730
|
+
for (let depth = 0; depth < 8 && current !== void 0 && !seen.has(current); depth += 1) {
|
|
731
|
+
if (current instanceof QlooResolutionProviderError)
|
|
732
|
+
return current;
|
|
733
|
+
seen.add(current);
|
|
734
|
+
current = current !== null && typeof current === "object" ? Reflect.get(current, "cause") : void 0;
|
|
735
|
+
}
|
|
736
|
+
return void 0;
|
|
737
|
+
}
|
|
738
|
+
function classifyExecutionFailure(error) {
|
|
739
|
+
const resolverError = resolutionProviderErrorInChain(error);
|
|
740
|
+
if (resolverError) {
|
|
741
|
+
if (resolverError.code === "RESOLVER_ABORTED") {
|
|
742
|
+
return {
|
|
743
|
+
code: "CANCELLED",
|
|
744
|
+
layer: "resolver",
|
|
745
|
+
retryable: false,
|
|
746
|
+
expected: true,
|
|
747
|
+
recovery: resolverError.recovery
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
const code = resolverError.code === "RESOLVER_AUTH" ? "RESOLVER_AUTH" : resolverError.code === "RESOLVER_CONNECT" ? "RESOLVER_CONNECT" : resolverError.code === "RESOLVER_TIMEOUT" ? "RESOLVER_TIMEOUT" : resolverError.code === "RESOLVER_UPSTREAM" ? "RESOLVER_UPSTREAM" : "RESOLVER_CONTRACT";
|
|
751
|
+
return {
|
|
752
|
+
code,
|
|
753
|
+
layer: "resolver",
|
|
754
|
+
retryable: resolverError.retryable,
|
|
755
|
+
expected: true,
|
|
756
|
+
recovery: resolverError.recovery
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
const clientError = qlooClientErrorInChain(error);
|
|
760
|
+
if (clientError) {
|
|
761
|
+
if (clientError.code === "QLOO_ABORTED") {
|
|
762
|
+
return {
|
|
763
|
+
code: "CANCELLED",
|
|
764
|
+
layer: "qloo",
|
|
765
|
+
retryable: false,
|
|
766
|
+
expected: true,
|
|
767
|
+
recovery: "Retry only if the Qloo request was cancelled unintentionally."
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
if (clientError.code === "QLOO_DNS_ERROR") {
|
|
771
|
+
return {
|
|
772
|
+
code: "QLOO_DNS",
|
|
773
|
+
layer: "qloo",
|
|
774
|
+
retryable: true,
|
|
775
|
+
expected: true,
|
|
776
|
+
recovery: "Run qloo doctor --network and verify the VPN-provided DNS route."
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
if (clientError.code === "QLOO_TIMEOUT") {
|
|
780
|
+
return {
|
|
781
|
+
code: "QLOO_TIMEOUT",
|
|
782
|
+
layer: "qloo",
|
|
783
|
+
retryable: true,
|
|
784
|
+
expected: true,
|
|
785
|
+
recovery: "Run qloo doctor --network; retry after confirming VPN routing and service reachability."
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
if (clientError.code === "QLOO_TLS_ERROR") {
|
|
789
|
+
return {
|
|
790
|
+
code: "QLOO_TLS",
|
|
791
|
+
layer: "qloo",
|
|
792
|
+
retryable: false,
|
|
793
|
+
expected: true,
|
|
794
|
+
recovery: "Run qloo doctor --network and correct the local trust or proxy configuration before retrying."
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
if (clientError.code === "QLOO_HTTP_ERROR") {
|
|
798
|
+
const status = clientError.status;
|
|
799
|
+
if (status === 401 || status === 403) {
|
|
800
|
+
return {
|
|
801
|
+
code: "QLOO_AUTH",
|
|
802
|
+
layer: "qloo",
|
|
803
|
+
retryable: false,
|
|
804
|
+
expected: true,
|
|
805
|
+
recovery: "Run qloo doctor and configure a valid Qloo API credential before retrying."
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
if (status === 429) {
|
|
809
|
+
return {
|
|
810
|
+
code: "QLOO_RATE_LIMIT",
|
|
811
|
+
layer: "qloo",
|
|
812
|
+
retryable: true,
|
|
813
|
+
expected: true,
|
|
814
|
+
recovery: "Wait for the Qloo rate-limit window, then retry the same interpreted request once."
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
return status !== void 0 && status >= 500 ? {
|
|
818
|
+
code: "QLOO_UPSTREAM",
|
|
819
|
+
layer: "qloo",
|
|
820
|
+
retryable: true,
|
|
821
|
+
expected: true,
|
|
822
|
+
recovery: "Retry once after the Qloo service recovers; use qloo doctor --network if it persists."
|
|
823
|
+
} : {
|
|
824
|
+
code: "QLOO_CONTRACT",
|
|
825
|
+
layer: "qloo",
|
|
826
|
+
retryable: false,
|
|
827
|
+
expected: true,
|
|
828
|
+
recovery: "Inspect qloo_capabilities and the linked Qloo documentation before changing the request."
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
if (clientError.code === "QLOO_CONFIGURATION_ERROR" || clientError.code === "QLOO_RESPONSE_ERROR" || clientError.code === "QLOO_RESPONSE_TOO_LARGE") {
|
|
832
|
+
return {
|
|
833
|
+
code: "QLOO_CONTRACT",
|
|
834
|
+
layer: "qloo",
|
|
835
|
+
retryable: false,
|
|
836
|
+
expected: true,
|
|
837
|
+
recovery: "Inspect qloo_capabilities, endpoint trust, and the current Qloo contract before retrying."
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
return {
|
|
841
|
+
code: "QLOO_CONNECT",
|
|
842
|
+
layer: "qloo",
|
|
843
|
+
retryable: clientError.retryable,
|
|
844
|
+
expected: true,
|
|
845
|
+
recovery: "Run qloo doctor --network and verify VPN, proxy, routing, and firewall configuration."
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
849
|
+
return {
|
|
850
|
+
code: "CANCELLED",
|
|
851
|
+
layer: "transport",
|
|
852
|
+
retryable: false,
|
|
853
|
+
expected: true,
|
|
854
|
+
recovery: "Retry only if the operation was cancelled unintentionally."
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
return {
|
|
858
|
+
code: "HARNESS_INTERNAL",
|
|
859
|
+
layer: "harness",
|
|
860
|
+
retryable: false,
|
|
861
|
+
expected: false,
|
|
862
|
+
recovery: "Run qloo doctor and inspect the local workflow trace before retrying."
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
var correlationCounter = 0;
|
|
866
|
+
function defaultCorrelationId() {
|
|
867
|
+
correlationCounter = (correlationCounter + 1) % Number.MAX_SAFE_INTEGER;
|
|
868
|
+
return `qloo-${Date.now().toString(36)}-${correlationCounter.toString(36)}`;
|
|
869
|
+
}
|
|
870
|
+
function normalizeResult(operation, input, value, transport, correlationId, durationMs) {
|
|
871
|
+
const provenance = value.provenance !== null && typeof value.provenance === "object" && !Array.isArray(value.provenance) ? value.provenance : void 0;
|
|
872
|
+
return {
|
|
873
|
+
...value,
|
|
874
|
+
schema_version: QLOO_TOOL_RESULT_SCHEMA_VERSION,
|
|
875
|
+
operation,
|
|
876
|
+
query_intent: createQlooQueryIntent(operation, input),
|
|
877
|
+
...provenance ? { provenance: { ...provenance, transport: transport.kind } } : {},
|
|
878
|
+
execution: {
|
|
879
|
+
transport: transport.kind,
|
|
880
|
+
transport_name: transport.name,
|
|
881
|
+
correlation_id: correlationId,
|
|
882
|
+
duration_ms: durationMs
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function createDelegatingQlooWorkflowExecutor(options) {
|
|
887
|
+
const now = options.now ?? Date.now;
|
|
888
|
+
const createCorrelationId = options.createCorrelationId ?? defaultCorrelationId;
|
|
889
|
+
return {
|
|
890
|
+
transport: options.transport,
|
|
891
|
+
...options.resolution ? { resolution: options.resolution } : {},
|
|
892
|
+
async execute(operation, input, context = {}) {
|
|
893
|
+
const correlationId = context.correlationId?.trim() || createCorrelationId();
|
|
894
|
+
const startedAt = now();
|
|
895
|
+
const validation = validateQlooWorkflowInput(operation, input);
|
|
896
|
+
if (!validation.ok) {
|
|
897
|
+
const issueSummary = validation.issues.map(({ path, message }) => `${path}: ${message}`).join("; ");
|
|
898
|
+
const wrapped = new QlooWorkflowExecutionError(operation, options.transport, `Invalid ${operation} input: ${issueSummary}`, void 0, {
|
|
899
|
+
code: "TOOL_INPUT",
|
|
900
|
+
layer: "tool_input",
|
|
901
|
+
expected: true,
|
|
902
|
+
recovery: "Correct the reported tool arguments and submit the operation once more.",
|
|
903
|
+
correlationId,
|
|
904
|
+
durationMs: Math.max(0, Math.round(now() - startedAt))
|
|
905
|
+
});
|
|
906
|
+
await Promise.resolve(options.observer?.onFailure?.({
|
|
907
|
+
operation,
|
|
908
|
+
transport: options.transport,
|
|
909
|
+
correlationId,
|
|
910
|
+
durationMs: wrapped.durationMs ?? 0,
|
|
911
|
+
error: wrapped
|
|
912
|
+
})).catch(() => void 0);
|
|
913
|
+
throw wrapped;
|
|
914
|
+
}
|
|
915
|
+
try {
|
|
916
|
+
const value = await options.invoke(operation, validation.value, {
|
|
917
|
+
...context,
|
|
918
|
+
correlationId
|
|
919
|
+
});
|
|
920
|
+
const durationMs = Math.max(0, Math.round(now() - startedAt));
|
|
921
|
+
const result = normalizeResult(operation, validation.value, value, options.transport, correlationId, durationMs);
|
|
922
|
+
const resultValidation = validateQlooWorkflowResult(result);
|
|
923
|
+
if (!resultValidation.ok) {
|
|
924
|
+
const issueSummary = resultValidation.issues.map(({ path, message }) => `${path}: ${message}`).join("; ");
|
|
925
|
+
throw new Error(`Executor produced an invalid ${operation} result: ${issueSummary}`);
|
|
926
|
+
}
|
|
927
|
+
const execution = {
|
|
928
|
+
operation,
|
|
929
|
+
transport: options.transport,
|
|
930
|
+
correlationId,
|
|
931
|
+
durationMs,
|
|
932
|
+
result
|
|
933
|
+
};
|
|
934
|
+
await Promise.resolve(options.observer?.onExecution?.(execution)).catch(() => void 0);
|
|
935
|
+
return execution;
|
|
936
|
+
} catch (error) {
|
|
937
|
+
const durationMs = Math.max(0, Math.round(now() - startedAt));
|
|
938
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
939
|
+
const classification = error instanceof QlooWorkflowExecutionError ? {
|
|
940
|
+
code: error.code,
|
|
941
|
+
layer: error.layer,
|
|
942
|
+
retryable: error.retryable,
|
|
943
|
+
expected: error.expected,
|
|
944
|
+
recovery: error.recovery
|
|
945
|
+
} : classifyExecutionFailure(error);
|
|
946
|
+
const wrapped = new QlooWorkflowExecutionError(operation, options.transport, `${options.transport.name} could not execute qloo_${operation}: ${message}`, error, { ...classification, correlationId, durationMs });
|
|
947
|
+
await Promise.resolve(options.observer?.onFailure?.({
|
|
948
|
+
operation,
|
|
949
|
+
transport: options.transport,
|
|
950
|
+
correlationId,
|
|
951
|
+
durationMs,
|
|
952
|
+
error: wrapped
|
|
953
|
+
})).catch(() => void 0);
|
|
954
|
+
throw wrapped;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
function createCliQlooWorkflowExecutor(invoke) {
|
|
960
|
+
return createDelegatingQlooWorkflowExecutor({
|
|
961
|
+
transport: { kind: "cli", name: "embedded Qloo CLI" },
|
|
962
|
+
invoke
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function createMcpQlooWorkflowExecutor(invoke, name = "Qloo MCP server") {
|
|
966
|
+
return createDelegatingQlooWorkflowExecutor({
|
|
967
|
+
transport: { kind: "mcp", name, remote: true },
|
|
968
|
+
invoke
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
export {
|
|
972
|
+
QlooWorkflowExecutionError,
|
|
973
|
+
createCliQlooWorkflowExecutor,
|
|
974
|
+
createDelegatingQlooWorkflowExecutor,
|
|
975
|
+
createMcpQlooWorkflowExecutor
|
|
976
|
+
};
|