@workglow/test-contract 0.6.1

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.
Files changed (149) hide show
  1. package/README.md +232 -0
  2. package/dist/ai-provider/assertions/capabilityHonesty.d.ts +7 -0
  3. package/dist/ai-provider/assertions/dispose.d.ts +7 -0
  4. package/dist/ai-provider/assertions/inferAdvertisesRegistered.d.ts +15 -0
  5. package/dist/ai-provider/assertions/inferServesInferred.d.ts +20 -0
  6. package/dist/ai-provider/assertions/pricingMatchesModality.d.ts +36 -0
  7. package/dist/ai-provider/assertions/registryCoverage.d.ts +13 -0
  8. package/dist/ai-provider/assertions/sessionReuse.d.ts +7 -0
  9. package/dist/ai-provider/assertions/signalHonoring.d.ts +7 -0
  10. package/dist/ai-provider/assertions/structuredGeneration.d.ts +7 -0
  11. package/dist/ai-provider/assertions/textGenerationSmoke.d.ts +7 -0
  12. package/dist/ai-provider/assertions/toolCallAccumulator.d.ts +7 -0
  13. package/dist/ai-provider/assertions/toolCallMultiTurn.d.ts +7 -0
  14. package/dist/ai-provider/assertions/usageNormalization.d.ts +61 -0
  15. package/dist/ai-provider/fixtures.d.ts +8 -0
  16. package/dist/ai-provider/runAiProviderConformance.d.ts +7 -0
  17. package/dist/ai-provider/types.d.ts +75 -0
  18. package/dist/ai-provider.d.ts +25 -0
  19. package/dist/ai-provider.js +876 -0
  20. package/dist/ai-provider.js.map +26 -0
  21. package/dist/browser-context/ConformanceMockContext.d.ts +54 -0
  22. package/dist/browser-context/assertions/ariaRoundTrip.d.ts +7 -0
  23. package/dist/browser-context/assertions/capabilityHonesty.d.ts +7 -0
  24. package/dist/browser-context/assertions/itExpectFail.d.ts +8 -0
  25. package/dist/browser-context/assertions/networkIntrospection.d.ts +7 -0
  26. package/dist/browser-context/assertions/tabsLifecycle.d.ts +7 -0
  27. package/dist/browser-context/fixtures.d.ts +8 -0
  28. package/dist/browser-context/runIBrowserContextConformance.d.ts +7 -0
  29. package/dist/browser-context/types.d.ts +48 -0
  30. package/dist/browser-context.d.ts +18 -0
  31. package/dist/browser-context.js +567 -0
  32. package/dist/browser-context.js.map +17 -0
  33. package/dist/creditExhaustedSkip.d.ts +39 -0
  34. package/dist/creditExhaustedSkip.js +163 -0
  35. package/dist/creditExhaustedSkip.js.map +10 -0
  36. package/dist/entitlement-profile/assertions/denialShape.d.ts +13 -0
  37. package/dist/entitlement-profile/assertions/dispose.d.ts +16 -0
  38. package/dist/entitlement-profile/assertions/hierarchyHonoring.d.ts +11 -0
  39. package/dist/entitlement-profile/assertions/optionalNeverDenied.d.ts +11 -0
  40. package/dist/entitlement-profile/assertions/requestEntitlementShape.d.ts +12 -0
  41. package/dist/entitlement-profile/assertions/resourceScoping.d.ts +16 -0
  42. package/dist/entitlement-profile/assertions/subscribeGrant.d.ts +11 -0
  43. package/dist/entitlement-profile/assertions/subscribeReload.d.ts +11 -0
  44. package/dist/entitlement-profile/assertions/subscribeRevocation.d.ts +12 -0
  45. package/dist/entitlement-profile/assertions/surfaceCoverage.d.ts +7 -0
  46. package/dist/entitlement-profile/assertions/unsubscribeIdempotent.d.ts +7 -0
  47. package/dist/entitlement-profile/fixtures.d.ts +21 -0
  48. package/dist/entitlement-profile/runEntitlementProfileConformance.d.ts +7 -0
  49. package/dist/entitlement-profile/types.d.ts +45 -0
  50. package/dist/entitlement-profile.d.ts +23 -0
  51. package/dist/entitlement-profile.js +436 -0
  52. package/dist/entitlement-profile.js.map +22 -0
  53. package/dist/human-connector/MockHumanConnector.d.ts +29 -0
  54. package/dist/human-connector/assertions/abort.d.ts +7 -0
  55. package/dist/human-connector/assertions/capabilityHonesty.d.ts +7 -0
  56. package/dist/human-connector/assertions/concurrentIsolation.d.ts +7 -0
  57. package/dist/human-connector/assertions/multiTurnFollowUp.d.ts +7 -0
  58. package/dist/human-connector/assertions/notifyDisplayFastResolve.d.ts +7 -0
  59. package/dist/human-connector/assertions/roundtrip.d.ts +7 -0
  60. package/dist/human-connector/fixtures.d.ts +8 -0
  61. package/dist/human-connector/runHumanConnectorConformance.d.ts +9 -0
  62. package/dist/human-connector/types.d.ts +91 -0
  63. package/dist/human-connector.d.ts +19 -0
  64. package/dist/human-connector.js +843 -0
  65. package/dist/human-connector.js.map +20 -0
  66. package/dist/itExpectFail.d.ts +15 -0
  67. package/dist/itExpectFail.js +180 -0
  68. package/dist/itExpectFail.js.map +11 -0
  69. package/dist/storage-migrations/assertions/appliesAndRecords.d.ts +7 -0
  70. package/dist/storage-migrations/assertions/concurrentRunsSerialize.d.ts +18 -0
  71. package/dist/storage-migrations/assertions/ensureBookkeepingIdempotent.d.ts +7 -0
  72. package/dist/storage-migrations/assertions/failedMigrationLeavesNoPartialSchema.d.ts +14 -0
  73. package/dist/storage-migrations/assertions/failedMigrationNotRecorded.d.ts +7 -0
  74. package/dist/storage-migrations/assertions/idempotentRun.d.ts +7 -0
  75. package/dist/storage-migrations/assertions/incrementalApplication.d.ts +7 -0
  76. package/dist/storage-migrations/runMigrationRunnerContract.d.ts +9 -0
  77. package/dist/storage-migrations/types.d.ts +78 -0
  78. package/dist/storage-migrations.d.ts +18 -0
  79. package/dist/storage-migrations.js +473 -0
  80. package/dist/storage-migrations.js.map +20 -0
  81. package/dist/tabular-migrations/assertions/addAndDropIndex.d.ts +7 -0
  82. package/dist/tabular-migrations/assertions/addColumn.d.ts +7 -0
  83. package/dist/tabular-migrations/assertions/backfill.d.ts +7 -0
  84. package/dist/tabular-migrations/assertions/dropColumn.d.ts +7 -0
  85. package/dist/tabular-migrations/assertions/failedMigrationNotRecorded.d.ts +7 -0
  86. package/dist/tabular-migrations/assertions/freshDbFastPath.d.ts +7 -0
  87. package/dist/tabular-migrations/assertions/incrementalApplication.d.ts +7 -0
  88. package/dist/tabular-migrations/assertions/renameColumn.d.ts +7 -0
  89. package/dist/tabular-migrations/runTabularMigrationContract.d.ts +8 -0
  90. package/dist/tabular-migrations/types.d.ts +28 -0
  91. package/dist/tabular-migrations.d.ts +19 -0
  92. package/dist/tabular-migrations.js +257 -0
  93. package/dist/tabular-migrations.js.map +18 -0
  94. package/dist/tabular-storage/assertions/countMatchesQuery.d.ts +7 -0
  95. package/dist/tabular-storage/assertions/guardParity.d.ts +25 -0
  96. package/dist/tabular-storage/assertions/inListCriterion.d.ts +14 -0
  97. package/dist/tabular-storage/assertions/joinBoundedLeftRead.d.ts +29 -0
  98. package/dist/tabular-storage/assertions/joinPushdown.d.ts +13 -0
  99. package/dist/tabular-storage/assertions/notInListCriterion.d.ts +15 -0
  100. package/dist/tabular-storage/assertions/strategyParity.d.ts +31 -0
  101. package/dist/tabular-storage/assertions/subscribeToChanges.d.ts +21 -0
  102. package/dist/tabular-storage/assertions/vectorColumnFormat.d.ts +7 -0
  103. package/dist/tabular-storage/assertions/withConnectionTransaction.d.ts +7 -0
  104. package/dist/tabular-storage/assertions/withTransactionRollback.d.ts +7 -0
  105. package/dist/tabular-storage/fixtures.d.ts +33 -0
  106. package/dist/tabular-storage/joinFixtures.d.ts +66 -0
  107. package/dist/tabular-storage/runTabularJoinContract.d.ts +24 -0
  108. package/dist/tabular-storage/runTabularStorageContract.d.ts +9 -0
  109. package/dist/tabular-storage/types.d.ts +102 -0
  110. package/dist/tabular-storage.d.ts +25 -0
  111. package/dist/tabular-storage.js +1477 -0
  112. package/dist/tabular-storage.js.map +27 -0
  113. package/dist/vector-storage/assertions/dimensionValidation.d.ts +17 -0
  114. package/dist/vector-storage/assertions/legacyEncoding.d.ts +16 -0
  115. package/dist/vector-storage/assertions/metadataFilter.d.ts +16 -0
  116. package/dist/vector-storage/assertions/searchOptions.d.ts +16 -0
  117. package/dist/vector-storage/assertions/shared.d.ts +23 -0
  118. package/dist/vector-storage/assertions/similarityRanking.d.ts +18 -0
  119. package/dist/vector-storage/assertions/similaritySearchEvent.d.ts +16 -0
  120. package/dist/vector-storage/assertions/vectorRoundTrip.d.ts +17 -0
  121. package/dist/vector-storage/runVectorStorageContract.d.ts +20 -0
  122. package/dist/vector-storage/types.d.ts +87 -0
  123. package/dist/vector-storage.d.ts +19 -0
  124. package/dist/vector-storage.js +412 -0
  125. package/dist/vector-storage.js.map +21 -0
  126. package/dist/web-search/assertions/capabilityAgreement.d.ts +23 -0
  127. package/dist/web-search/assertions/credentialNaming.d.ts +21 -0
  128. package/dist/web-search/assertions/dateFiltering.d.ts +22 -0
  129. package/dist/web-search/assertions/domainNormalization.d.ts +24 -0
  130. package/dist/web-search/assertions/maxResultsCeiling.d.ts +22 -0
  131. package/dist/web-search/assertions/reportedQuery.d.ts +18 -0
  132. package/dist/web-search/assertions/signalThreading.d.ts +20 -0
  133. package/dist/web-search/fixtures.d.ts +40 -0
  134. package/dist/web-search/runWebSearchProviderConformance.d.ts +24 -0
  135. package/dist/web-search/types.d.ts +79 -0
  136. package/dist/web-search.d.ts +19 -0
  137. package/dist/web-search.js +560 -0
  138. package/dist/web-search.js.map +18 -0
  139. package/dist/worker-proxy/assertions/backlogOrdering.d.ts +7 -0
  140. package/dist/worker-proxy/assertions/disposeTerminatesWorker.d.ts +8 -0
  141. package/dist/worker-proxy/assertions/errorPropagation.d.ts +7 -0
  142. package/dist/worker-proxy/assertions/providerCallHelpers.d.ts +23 -0
  143. package/dist/worker-proxy/browserOnlyStub.d.ts +7 -0
  144. package/dist/worker-proxy/runWorkerProxyBoundary.d.ts +7 -0
  145. package/dist/worker-proxy/types.d.ts +47 -0
  146. package/dist/worker-proxy.d.ts +16 -0
  147. package/dist/worker-proxy.js +389 -0
  148. package/dist/worker-proxy.js.map +17 -0
  149. package/package.json +120 -0
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/web-search/assertions/capabilityAgreement.ts", "../src/web-search/fixtures.ts", "../src/web-search/assertions/credentialNaming.ts", "../src/web-search/assertions/dateFiltering.ts", "../src/web-search/assertions/domainNormalization.ts", "../src/web-search/assertions/maxResultsCeiling.ts", "../src/web-search/assertions/reportedQuery.ts", "../src/web-search/assertions/signalThreading.ts", "../src/web-search/runWebSearchProviderConformance.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { WebSearchCapabilities } from \"@workglow/web-search\";\nimport { unhonorableOptions, WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { PROBE_QUERY, registerOnly } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/**\n * The option fields as `WebSearchTask` takes them, which is where every probe\n * is spent. Written out rather than reused from `WebSearchRequest`: the task's\n * input schema carries mutable arrays and the provider request readonly ones,\n * and a probe has to satisfy both.\n */\ninterface ProbeOptions {\n readonly includeDomains?: string[];\n readonly excludeDomains?: string[];\n readonly dateRange?: { readonly start?: string; readonly end?: string };\n readonly includeAnswer?: boolean;\n readonly includeContent?: boolean;\n}\n\n/**\n * One request shape, and the name the capability check reports it under.\n *\n * Every option `unhonorableOptions` can name is probed, plus the pair it\n * reports only in combination. The list is checked against that function's own\n * vocabulary below rather than trusted, so an option added to the capability\n * record cannot quietly go unprobed.\n */\ninterface Probe {\n readonly label: string;\n readonly request: ProbeOptions;\n}\n\nfunction probesFor(domain: string): readonly Probe[] {\n return [\n { label: \"includeDomains\", request: { includeDomains: [domain] } },\n { label: \"excludeDomains\", request: { excludeDomains: [domain] } },\n {\n label: \"includeDomains with excludeDomains\",\n request: { includeDomains: [domain], excludeDomains: [\"elsewhere.example\"] },\n },\n { label: \"dateRange\", request: { dateRange: { start: \"2024-01-01\", end: \"2024-12-31\" } } },\n { label: \"includeAnswer\", request: { includeAnswer: true } },\n { label: \"includeContent\", request: { includeContent: true } },\n ];\n}\n\n/**\n * What a provider declares is what it is asked to do, and nothing else.\n *\n * `WebSearchCapabilities` is a promise made to the router: an option the record\n * says the provider cannot serve must be refused BEFORE the vendor is reached,\n * and an option it says the provider can serve must actually be attempted. Both\n * halves fail quietly on their own. Under-declaring loses working behaviour to\n * `\"auto\"` routing, which walks past the provider that could have served the\n * request; over-declaring is worse, because the request is routed here and the\n * adapter throws — or, in the failure this whole record exists to prevent,\n * silently drops the option and reports a search that ran without it.\n *\n * Asserted by reading the record rather than by listing what each provider\n * does. That is the only version of this test that stays true when a provider\n * changes what it supports, which is the event it exists to catch.\n */\nexport function capabilityAgreementBlock(opts: WebSearchProviderConformanceOpts): void {\n const domain = opts.sampleDomain ?? \"example.com\";\n const probes = probesFor(domain);\n\n describe(\"capability agreement\", () => {\n let harness: WebSearchConformanceHarness;\n\n beforeEach(async () => {\n harness = await opts.createHarness({ resultCount: 2 });\n registerOnly(harness);\n });\n\n afterEach(() => harness.dispose());\n\n it(\n \"probes every option the capability check can refuse\",\n () => {\n // The ratchet. `unhonorableOptions` is the vocabulary, so a gap it can\n // report that no probe produces is an option this block would never\n // ask about — and the whole record would look agreed-upon.\n const everything: WebSearchCapabilities = {\n answer: false,\n content: false,\n domainFilter: false,\n excludeDomainFilter: false,\n exclusiveDomainDirections: true,\n dateFilter: false,\n maxResultsCap: undefined,\n };\n const reachable = new Set<string>();\n for (const probe of probes) {\n for (const gap of unhonorableOptions(everything, {\n query: PROBE_QUERY,\n ...probe.request,\n })) {\n reachable.add(gap);\n }\n }\n // The pair is only reported when neither direction is refused on its\n // own, so a record that refuses both never names it. Probe it against a\n // record that serves each direction separately instead.\n for (const gap of unhonorableOptions(\n { ...everything, domainFilter: \"native\", excludeDomainFilter: \"native\" },\n { query: PROBE_QUERY, includeDomains: [domain], excludeDomains: [\"elsewhere.example\"] }\n )) {\n reachable.add(gap);\n }\n expect([...reachable].sort()).toEqual(probes.map((p) => p.label).sort());\n },\n opts.timeout\n );\n\n for (const probe of probes) {\n it(\n `agrees with its own record about ${probe.label}`,\n async () => {\n const declared = unhonorableOptions(harness.provider.capabilities, {\n query: PROBE_QUERY,\n ...probe.request,\n });\n const run = new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n ...probe.request,\n });\n\n if (declared.length > 0) {\n await expect(run).rejects.toThrow(\n new RegExp(declared.map((g) => g.replace(/\\s/g, \"\\\\s\")).join(\"|\"))\n );\n // Refused BEFORE the call, not by the vendor afterwards: a request\n // that reached the wire was billed, and its failure arrives as\n // whatever the vendor says rather than as the option that was wrong.\n expect(harness.sent()).toEqual([]);\n } else {\n const output = await run;\n expect(harness.sent().length).toBeGreaterThan(0);\n // Attempting it is not serving it. `answer` and `content` are the\n // two options whose result is visible on the output, so a provider\n // declaring either has to produce it from a payload that carries\n // one — otherwise \"supported\" means the option was forwarded and\n // the response quietly came back without it, which is the same\n // silent drop over-declaring a domain filter produces.\n if (probe.request.includeAnswer === true) {\n expect(output.answer).toBeTruthy();\n }\n if (probe.request.includeContent === true) {\n expect(output.results.some((result) => Boolean(result.content))).toBe(true);\n }\n }\n },\n opts.timeout\n );\n }\n });\n}\n",
6
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { IWebSearchProvider, WebSearchRequest } from \"@workglow/web-search\";\nimport { WebSearchProviderRegistry } from \"@workglow/web-search\";\nimport type { WebSearchConformanceHarness } from \"./types\";\n\n/** The query every assertion searches for, so a rewrite of it is visible. */\nexport const PROBE_QUERY = \"transformer architecture\";\n\n/**\n * A provider registered beside the one under test, so `\"auto\"` has somewhere\n * else to land and a credential can be named for a vendor that is not this one.\n *\n * It declares everything, which is what makes it a useful foil: routing prefers\n * a provider a key is named for, so a decoy that could serve the request is the\n * only way to catch a key reaching the wrong vendor.\n */\nexport function decoyProvider(\n name: string,\n onSearch?: (r: WebSearchRequest) => void\n): IWebSearchProvider {\n return {\n name,\n endpoint: `https://${name}.invalid`,\n acceptsCredentialKey: true,\n capabilities: {\n answer: true,\n content: true,\n domainFilter: \"native\",\n dateFilter: true,\n maxResultsCap: undefined,\n },\n search: async (request) => {\n onSearch?.(request);\n return {\n results: [{ title: \"decoy\", url: `https://${name}.invalid/a` }],\n query: request.query,\n };\n },\n };\n}\n\n/** Registers the provider under test alone, the state most assertions want. */\nexport function registerOnly(harness: WebSearchConformanceHarness): void {\n WebSearchProviderRegistry.clear();\n WebSearchProviderRegistry.register(harness.provider);\n}\n\n/**\n * Whether a domain restriction reaches this provider as a list or as `site:`\n * operators spliced into the query. The exclude direction defaults to the\n * include direction, exactly as the task reads it.\n */\nexport function domainRoutes(provider: IWebSearchProvider): {\n readonly include: \"native\" | \"query-operator\" | false;\n readonly exclude: \"native\" | \"query-operator\" | false;\n} {\n const capabilities = provider.capabilities;\n return {\n include: capabilities.domainFilter,\n exclude: capabilities.excludeDomainFilter ?? capabilities.domainFilter,\n };\n}\n\n/**\n * Percent-decoded, with `+` read as a space, or the input unchanged when it\n * carries a sequence that is not valid encoding.\n */\nfunction decodeLoosely(text: string): string {\n try {\n return decodeURIComponent(text.replace(/\\+/g, \" \"));\n } catch {\n return text;\n }\n}\n\n/**\n * Everything one search sent, as a single string to look for a substring in.\n *\n * The decoded rendering is appended rather than substituted, so a value matches\n * whichever way this provider carried it. One sends `site:example.com` in a\n * JSON body and the next sends `site%3Aexample.com` in a query string; both are\n * the same restriction, and a suite that reads only the raw bytes would report\n * the second as a restriction that never left. Appending keeps the equality\n * assertions exact — two sends are equal here only if their raw forms were.\n */\nexport function sentText(harness: WebSearchConformanceHarness): string {\n const raw = harness.sent().join(\"\\n\");\n return `${raw}\\n${decodeLoosely(raw)}`;\n}\n",
7
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { WebSearchProviderRegistry, WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { decoyProvider, PROBE_QUERY, registerOnly, sentText } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\nconst DECOY = \"conformance-decoy\";\nconst SECRET_KEY = \"conformance-key-for-the-decoy\";\n\n/**\n * A credential is named for a provider, never for the request.\n *\n * `credential_keys` maps provider name to credential-store key, and the key\n * sent is the one named for the provider that RAN — so a key issued for one\n * vendor cannot leave with a request to another. That is not a tidiness rule:\n * a search API key is a bearer credential against a metered account, and one\n * forwarded to the wrong vendor has been disclosed to them.\n *\n * The bare `credential_key` port survives for a pinned provider, where the\n * vendor is unambiguous, and is refused under `\"auto\"` for the same reason:\n * routing picks the vendor at run time, so an unnamed key goes wherever it\n * lands.\n */\nexport function credentialNamingBlock(opts: WebSearchProviderConformanceOpts): void {\n describe(\"credential naming\", () => {\n let harness: WebSearchConformanceHarness;\n\n beforeEach(async () => {\n harness = await opts.createHarness({ resultCount: 2 });\n registerOnly(harness);\n });\n\n afterEach(() => {\n harness.dispose();\n WebSearchProviderRegistry.clear();\n });\n\n it(\n \"refuses a bare credential_key under auto\",\n async () => {\n await expect(\n new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: \"auto\",\n credential_key: SECRET_KEY,\n })\n ).rejects.toThrow(/credential_key.*auto|auto.*credential_key/s);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n\n it(\n \"never sends a key named for another provider\",\n async () => {\n let decoyRan = false;\n WebSearchProviderRegistry.register(\n decoyProvider(DECOY, () => {\n decoyRan = true;\n })\n );\n\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n credential_keys: { [DECOY]: SECRET_KEY },\n });\n\n expect(decoyRan).toBe(false);\n // The pinned provider ran, and the decoy's key did not go with it.\n expect(sentText(harness)).not.toContain(SECRET_KEY);\n },\n opts.timeout\n );\n\n it(\n \"refuses a key named for a provider that is not registered\",\n async () => {\n await expect(\n new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n credential_keys: { \"not-a-provider\": SECRET_KEY },\n })\n ).rejects.toThrow(/not a .*registered provider/s);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n\n it(\n \"says so when this provider never receives a credential key\",\n async () => {\n const run = new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n credential_keys: { [harness.provider.name]: SECRET_KEY },\n });\n\n if (harness.provider.acceptsCredentialKey) {\n await expect(run).resolves.toBeDefined();\n return;\n }\n // An adapter authenticating through its own vendor client ignores the\n // field, so naming a key for it is refused rather than dropped in\n // silence — a caller who thinks they configured auth and did not is how\n // a request goes out unauthenticated and nobody hears about it.\n await expect(run).rejects.toThrow(/never receives a credential-store key/);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n\n it(\n \"prefers a provider a key is named for when routing\",\n async () => {\n let decoyRan = false;\n WebSearchProviderRegistry.register(\n decoyProvider(DECOY, () => {\n decoyRan = true;\n })\n );\n\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: \"auto\",\n credential_keys: { [DECOY]: SECRET_KEY },\n });\n\n // Naming a key states which vendors the caller actually holds one for.\n // Without this preference, routing lands on whoever registered first\n // and the request goes out unauthenticated while a usable key sits\n // behind it.\n expect(out.provider).toBe(DECOY);\n expect(decoyRan).toBe(true);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n });\n}\n",
8
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { PROBE_QUERY, registerOnly, sentText } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/**\n * The distinct calendar dates one request carried, however the vendor spelled\n * them — a bare `YYYY-MM-DD`, a slice of an RFC-3339 timestamp, or two of them\n * run together in one parameter.\n *\n * Distinct, because `sentText` renders what went out twice (raw and decoded),\n * and counting the bounds is the whole point.\n */\nfunction datesIn(text: string): string[] {\n return [...new Set(text.match(/\\d{4}-\\d{2}-\\d{2}/g) ?? [])];\n}\n\n/** The three shapes `dateRange` arrives in: closed, open at the start, open at the end. */\nconst RANGES = [\n { label: \"a closed range\", value: { start: \"2024-01-01\", end: \"2024-06-30\" } },\n { label: \"a range open at the start\", value: { end: \"2024-06-30\" } },\n { label: \"a range open at the end\", value: { start: \"2024-01-01\" } },\n] as const;\n\n/**\n * Date filtering is never emulated, and never half-sent.\n *\n * Post-filtering by `publishedDate` breaks `maxResults` and drops every result\n * whose date the provider omitted, so a provider that cannot filter server-side\n * declares `dateFilter: false` and such a request is refused rather than\n * approximated. That is the half most people expect.\n *\n * The other half is what a provider declaring `true` then owes: something for\n * EVERY range this task accepts. The real APIs take closed intervals — Brave's\n * `freshness`, Gemini's `timeRangeFilter` — so a half-open range has to be\n * filled at the open end. Dropping it instead reports a bound as honored on a\n * search that ran unfiltered, which is the failure the refusal above exists to\n * avoid, arrived at by a different road.\n */\nexport function dateFilteringBlock(opts: WebSearchProviderConformanceOpts): void {\n describe(\"date filtering\", () => {\n let harness: WebSearchConformanceHarness;\n\n afterEach(() => harness?.dispose());\n\n for (const range of RANGES) {\n it(\n `never emulates ${range.label}`,\n async () => {\n harness = await opts.createHarness({ resultCount: 3 });\n registerOnly(harness);\n const run = new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n dateRange: { ...range.value },\n });\n\n if (!harness.provider.capabilities.dateFilter) {\n await expect(run).rejects.toThrow(/dateRange/);\n expect(harness.sent()).toEqual([]);\n return;\n }\n\n await expect(run).resolves.toBeDefined();\n const withRange = sentText(harness);\n harness.dispose();\n\n const plain = await opts.createHarness({ resultCount: 3 });\n registerOnly(plain);\n try {\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: plain.provider.name,\n });\n // The bound reached the wire in whatever shape this vendor takes.\n // An open end filled with a default still changes what is sent; an\n // open end DROPPED does not, which is the whole failure.\n expect(withRange).not.toEqual(sentText(plain));\n } finally {\n plain.dispose();\n }\n },\n opts.timeout\n );\n }\n\n it(\n \"fills the open end of a half-open range rather than sending it half\",\n async () => {\n harness = await opts.createHarness({ resultCount: 3 });\n registerOnly(harness);\n if (!harness.provider.capabilities.dateFilter) return;\n\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n dateRange: { start: \"2024-01-01\" },\n });\n const openEnded = datesIn(sentText(harness));\n\n // The bound the caller actually named reaches the wire either way.\n expect(openEnded).toContain(\"2024-01-01\");\n\n if (!opts.fillsOpenDateBounds) {\n // An API taking each bound separately is honoring the request by\n // sending the one it was given; there is no end to fill.\n return;\n }\n // A closed interval has to carry two. Sending one is the failure this\n // whole block exists for: the request goes out unfiltered at the open\n // end while `dateFilter: true` reports the bound as honored — and\n // asserting only that the START appears cannot tell the two apart,\n // because a provider that drops the end still sends the start.\n expect(openEnded.length).toBeGreaterThanOrEqual(2);\n },\n opts.timeout\n );\n\n it(\n \"fills the open start of a half-open range too\",\n async () => {\n harness = await opts.createHarness({ resultCount: 3 });\n registerOnly(harness);\n if (!harness.provider.capabilities.dateFilter) return;\n\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n dateRange: { end: \"2024-06-30\" },\n });\n const openStart = datesIn(sentText(harness));\n\n expect(openStart).toContain(\"2024-06-30\");\n if (!opts.fillsOpenDateBounds) return;\n // The other direction, which a provider can get wrong on its own: an\n // adapter filling only the end reads as correct on the case above.\n expect(openStart.length).toBeGreaterThanOrEqual(2);\n },\n opts.timeout\n );\n });\n}\n",
9
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { domainRoutes, PROBE_QUERY, registerOnly, sentText } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/** Spellings of one host that must all reduce to the same restriction. */\nconst SPELLINGS = [\"https://Example.COM/\", \"www.example.com\", \"EXAMPLE.com\", \"example.com/\"];\n\n/**\n * Entries that name no domain. Each is a value a caller did not mean rather\n * than a malformed host — most often a list pasted into one array entry — and\n * there is no portable `site:` quoting that would rescue any of them.\n */\nconst UNUSABLE = [\"\", \" \", \"a.com b.com\", \"(example.com)\", 'ex\"ample.com', \"it's.com\"];\n\n/**\n * A domain entry means the same thing whichever route carries it.\n *\n * There are two routes — a native domain list, and a `site:` clause spliced\n * into the query — and the same entry has to reduce identically on both. It did\n * not once: reducing only on the way into an operator left `\"https://arxiv.org/\"`\n * restricting one route and reaching a vendor API scheme-first on the other,\n * where it matches nothing. Under `\"auto\"` the caller cannot even tell which\n * route ran, so the search comes back successful, reports the provider, and\n * silently searched the whole web.\n *\n * An unusable entry is refused for the same reason, and for EVERY provider\n * rather than only the ones translating to `site:`. Dropping it is the same\n * trade one step worse: the translation emits no clause for an empty list and\n * the task clears the list afterwards, so one bad entry in a one-entry list\n * removes the restriction from both paths at once.\n */\nexport function domainNormalizationBlock(opts: WebSearchProviderConformanceOpts): void {\n describe(\"domain normalization\", () => {\n let harness: WebSearchConformanceHarness;\n\n beforeEach(async () => {\n harness = await opts.createHarness({ resultCount: 2 });\n registerOnly(harness);\n });\n\n afterEach(() => harness.dispose());\n\n const routes = (): ReturnType<typeof domainRoutes> => domainRoutes(harness.provider);\n\n it(\n \"reduces every spelling of one host to the same request\",\n async () => {\n if (routes().include === false) return;\n const sentFor = async (domain: string): Promise<string> => {\n const local = await opts.createHarness({ resultCount: 2 });\n registerOnly(local);\n try {\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: local.provider.name,\n includeDomains: [domain],\n });\n return sentText(local);\n } finally {\n local.dispose();\n }\n };\n\n const first = await sentFor(SPELLINGS[0]);\n for (const spelling of SPELLINGS.slice(1)) {\n expect(await sentFor(spelling)).toEqual(first);\n }\n },\n opts.timeout\n );\n\n it(\n \"carries the restriction to the wire rather than dropping it\",\n async () => {\n if (routes().include === false) return;\n const plain = await opts.createHarness({ resultCount: 2 });\n registerOnly(plain);\n await new WebSearchTask().run({ query: PROBE_QUERY, provider: plain.provider.name });\n const withoutFilter = sentText(plain);\n plain.dispose();\n\n registerOnly(harness);\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n includeDomains: [\"example.com\"],\n });\n // Whatever shape it takes — a list field or a `site:` clause — a\n // restriction the provider declared it can serve has to change what\n // goes out. A search that sends the same bytes either way ran\n // unfiltered and said nothing.\n expect(sentText(harness)).not.toEqual(withoutFilter);\n expect(sentText(harness)).toContain(\"example.com\");\n },\n opts.timeout\n );\n\n it(\n \"carries an exclude restriction to the wire rather than dropping it\",\n async () => {\n if (routes().exclude === false) return;\n const plain = await opts.createHarness({ resultCount: 2 });\n registerOnly(plain);\n await new WebSearchTask().run({ query: PROBE_QUERY, provider: plain.provider.name });\n const withoutFilter = sentText(plain);\n plain.dispose();\n\n registerOnly(harness);\n await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n excludeDomains: [\"blocked.example\"],\n });\n\n // The direction that is declared separately BECAUSE one real vendor\n // serves only the other: OpenAI's `web_search` takes\n // `filters.allowed_domains` and has no blocked equivalent. Claiming it\n // anyway is the over-declaration `excludeDomainFilter` exists to\n // prevent, and it does not throw — the adapter has nowhere to put the\n // list, drops it, and returns a search that reports the provider, the\n // query and a plausible result set with the restriction gone.\n expect(sentText(harness)).not.toEqual(withoutFilter);\n expect(sentText(harness)).toContain(\"blocked.example\");\n },\n opts.timeout\n );\n\n for (const entry of UNUSABLE) {\n it(\n `refuses includeDomains ${JSON.stringify(entry)} before the call`,\n async () => {\n await expect(\n new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n includeDomains: [entry],\n })\n ).rejects.toThrow(/names no domain|name no domain/);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n\n it(\n `refuses excludeDomains ${JSON.stringify(entry)} before the call`,\n async () => {\n await expect(\n new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n excludeDomains: [entry],\n })\n ).rejects.toThrow(/names no domain|name no domain/);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n }\n\n it(\n \"refuses a bad entry even beside good ones\",\n async () => {\n // The case that actually happens: a list where one line was pasted\n // wrong. Validating only single-entry lists would let the rest through\n // with a restriction the caller never agreed to.\n await expect(\n new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n includeDomains: [\"good.example\", \"a.com b.com\", \"also-good.example\"],\n })\n ).rejects.toThrow(/names no domain/);\n expect(harness.sent()).toEqual([]);\n },\n opts.timeout\n );\n });\n}\n",
10
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { PROBE_QUERY, registerOnly } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/**\n * `maxResults` is a ceiling, and it means the same thing on every route.\n *\n * It is the one option `unhonorableOptions` deliberately never reports: asking\n * for more results than a provider's cap is not a requirement the way a domain\n * restriction is, so an over-large value is clamped rather than refused. That\n * asymmetry is what makes the rest of it worth asserting — a provider is free\n * to return fewer, and never free to return more, and neither half is visible\n * to a caller who gets a plausible-looking list back.\n *\n * Three providers needed a fix for exactly this in one window, each found by\n * hand on its own route: an API with no result parameter has to apply the bound\n * itself after the fact, and every one that forgot returned whatever the vendor\n * felt like.\n */\nexport function maxResultsCeilingBlock(opts: WebSearchProviderConformanceOpts): void {\n describe(\"maxResults ceiling\", () => {\n let harness: WebSearchConformanceHarness;\n\n afterEach(() => harness?.dispose());\n\n beforeEach(() => {\n // Each case builds its own harness, since how many results the canned\n // answer carries is what it is varying.\n });\n\n it(\n \"never returns more results than asked for\",\n async () => {\n harness = await opts.createHarness({ resultCount: 9 });\n registerOnly(harness);\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n maxResults: 3,\n });\n expect(out.results.length).toBeLessThanOrEqual(3);\n expect(out.count).toBe(out.results.length);\n },\n opts.timeout\n );\n\n it(\n \"clamps a value over the provider's cap rather than refusing it\",\n async () => {\n harness = await opts.createHarness({ resultCount: 4 });\n registerOnly(harness);\n const cap = harness.provider.capabilities.maxResultsCap;\n const asked = (cap ?? 20) + 500;\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n maxResults: asked,\n });\n expect(out.results.length).toBeLessThanOrEqual(cap ?? asked);\n },\n opts.timeout\n );\n\n it(\n \"returns what it has when fewer results exist than asked for\",\n async () => {\n harness = await opts.createHarness({ resultCount: 2 });\n registerOnly(harness);\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n maxResults: 8,\n });\n // A ceiling, never a floor: padding to reach the number would invent\n // sources, which is the worse failure of the two.\n expect(out.results).toHaveLength(2);\n },\n opts.timeout\n );\n\n it(\n \"reports count as the number of results it actually returned\",\n async () => {\n harness = await opts.createHarness({ resultCount: 6 });\n registerOnly(harness);\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n maxResults: 2,\n });\n expect(out.count).toBe(out.results.length);\n },\n opts.timeout\n );\n });\n}\n",
11
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { WebSearchTask } from \"@workglow/web-search\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { domainRoutes, PROBE_QUERY, registerOnly, sentText } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/**\n * The `query` output port is the query that ran, and `provider` is who ran it.\n *\n * Both exist because the task rewrites one and chooses the other. A\n * `query-operator` provider has its domain restriction spliced into the query\n * as `site:` clauses, so the string that ran is not the string the caller\n * passed — and an adapter that echoes the input instead is reporting a search\n * that did not happen. Under `\"auto\"` the caller did not pick the vendor\n * either, so `provider` is the only record of which quota was spent and which\n * engine's ranking produced the list.\n */\nexport function reportedQueryBlock(opts: WebSearchProviderConformanceOpts): void {\n describe(\"reported query and provider\", () => {\n let harness: WebSearchConformanceHarness;\n\n beforeEach(async () => {\n harness = await opts.createHarness({ resultCount: 3 });\n registerOnly(harness);\n });\n\n afterEach(() => harness.dispose());\n\n it(\n \"reports the provider that ran when it was pinned\",\n async () => {\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n });\n expect(out.provider).toBe(harness.provider.name);\n },\n opts.timeout\n );\n\n it(\n \"reports the provider that ran when routing chose it\",\n async () => {\n const out = await new WebSearchTask().run({ query: PROBE_QUERY, provider: \"auto\" });\n expect(out.provider).toBe(harness.provider.name);\n },\n opts.timeout\n );\n\n it(\n \"reports the unmodified query when nothing rewrote it\",\n async () => {\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n });\n expect(out.query).toBe(PROBE_QUERY);\n },\n opts.timeout\n );\n\n it(\n \"reports the rewritten query when a domain restriction moved into it\",\n async () => {\n const routes = domainRoutes(harness.provider);\n if (routes.include !== \"query-operator\") return;\n\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n includeDomains: [\"example.com\"],\n });\n\n expect(out.query).toContain(\"site:example.com\");\n expect(out.query).not.toBe(PROBE_QUERY);\n // And it is the query that actually went out, not a second rendering of\n // the same idea: a provider reporting one string and sending another is\n // lying about what ran in the direction nobody checks.\n expect(sentText(harness)).toContain(\"site:example.com\");\n },\n opts.timeout\n );\n\n it(\n \"leaves the query alone when the restriction travels as a list\",\n async () => {\n const routes = domainRoutes(harness.provider);\n if (routes.include !== \"native\") return;\n\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: harness.provider.name,\n includeDomains: [\"example.com\"],\n });\n // Splicing operators into a query a native filter already covers would\n // restrict it twice, and the second restriction is invisible.\n expect(out.query).toBe(PROBE_QUERY);\n },\n opts.timeout\n );\n\n it(\n \"always reports results and a count, even with nothing to report\",\n async () => {\n const empty = await opts.createHarness({ resultCount: 0 });\n registerOnly(empty);\n try {\n const out = await new WebSearchTask().run({\n query: PROBE_QUERY,\n provider: empty.provider.name,\n });\n expect(Array.isArray(out.results)).toBe(true);\n expect(out.count).toBe(0);\n expect(out.provider).toBe(empty.provider.name);\n } finally {\n empty.dispose();\n }\n },\n opts.timeout\n );\n });\n}\n",
12
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { PROBE_QUERY, registerOnly } from \"../fixtures\";\nimport type { WebSearchConformanceHarness, WebSearchProviderConformanceOpts } from \"../types\";\n\n/**\n * The run's signal reaches the call, not just a check in front of it.\n *\n * A `throwIfAborted()` before the request answers the easy half — a run already\n * cancelled does not start one — and leaves the expensive half alone: a\n * cancelled run whose request is already in flight keeps it in flight, and a\n * grounded turn nobody is waiting for is still billed for every token it\n * generates. The signal has to be handed to the transport itself.\n *\n * Asserted on what the adapter passed outward rather than on how fast the\n * promise rejects. A rejection proves the task stopped waiting; only the signal\n * on the call proves the call stopped running.\n */\nexport function signalThreadingBlock(opts: WebSearchProviderConformanceOpts): void {\n describe.skipIf(!opts.signalReachesTransport)(\"signal threading\", () => {\n let harness: WebSearchConformanceHarness;\n\n beforeEach(async () => {\n harness = await opts.createHarness({ resultCount: 2 });\n registerOnly(harness);\n });\n\n afterEach(() => harness.dispose());\n\n it(\n \"hands the run's signal to the outbound call\",\n async () => {\n const controller = new AbortController();\n await harness.search({ query: PROBE_QUERY }, controller.signal);\n\n const signals = harness.signals();\n expect(signals.length).toBeGreaterThan(0);\n for (const signal of signals) {\n expect(signal).toBeDefined();\n expect(signal?.aborted).toBe(false);\n }\n // The run's own signal, not a fresh one the adapter made: a signal\n // nothing aborts is indistinguishable from no signal at all, and that\n // is exactly what a `throwIfAborted()` in front of an unsignalled call\n // looks like from outside.\n controller.abort();\n for (const signal of signals) {\n expect(signal?.aborted).toBe(true);\n }\n },\n opts.timeout\n );\n });\n}\n",
13
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe } from \"vitest\";\nimport { capabilityAgreementBlock } from \"./assertions/capabilityAgreement\";\nimport { credentialNamingBlock } from \"./assertions/credentialNaming\";\nimport { dateFilteringBlock } from \"./assertions/dateFiltering\";\nimport { domainNormalizationBlock } from \"./assertions/domainNormalization\";\nimport { maxResultsCeilingBlock } from \"./assertions/maxResultsCeiling\";\nimport { reportedQueryBlock } from \"./assertions/reportedQuery\";\nimport { signalThreadingBlock } from \"./assertions/signalThreading\";\nimport type { WebSearchProviderConformanceOpts } from \"./types\";\n\n/**\n * Everything an `IWebSearchProvider` owes a caller, over every adapter.\n *\n * Seven ship — three that own an HTTP fetch, four that reach a vendor SDK for\n * model-grounded search — and they had no shared assertions at all. What that\n * cost is legible in the package's own history: three of its twelve fixes in\n * one window were \"make property P true on every route\", each found by hand,\n * one route at a time, after the route that already had it was shipped. A\n * property that has to hold on every route is what a parameterized suite is\n * for.\n *\n * So the assertions are derived from `WebSearchCapabilities` rather than\n * written per provider. The record already declares what each adapter can do;\n * reading it and asserting the matching behaviour is what makes the suite still\n * true after a provider changes what it supports — which is the event worth\n * catching, and the one a hand-written expectation silently outlives.\n */\nexport function runWebSearchProviderConformance(opts: WebSearchProviderConformanceOpts): void {\n describe.skipIf(opts.skip)(`Web search provider contract: ${opts.name}`, () => {\n capabilityAgreementBlock(opts);\n maxResultsCeilingBlock(opts);\n domainNormalizationBlock(opts);\n dateFilteringBlock(opts);\n reportedQueryBlock(opts);\n signalThreadingBlock(opts);\n credentialNamingBlock(opts);\n });\n}\n"
14
+ ],
15
+ "mappings": "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",
16
+ "debugId": "C4B5C15DB8F13A3964756E2164756E21",
17
+ "names": []
18
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WorkerProxyBoundaryOpts } from "../types";
7
+ export declare function backlogOrderingBlock(opts: WorkerProxyBoundaryOpts): void;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceHandle } from "../../ai-provider/types";
7
+ import type { WorkerProxyBoundaryOpts } from "../types";
8
+ export declare function disposeTerminatesWorkerBlock(opts: WorkerProxyBoundaryOpts, getHandle: () => ConformanceHandle, markDisposed: () => void): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WorkerProxyBoundaryOpts } from "../types";
7
+ export declare function errorPropagationBlock(opts: WorkerProxyBoundaryOpts): void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { collectStream } from "@workglow/ai";
7
+ export interface CallOpts {
8
+ readonly maxTokens: number;
9
+ readonly timeoutMs: number;
10
+ readonly signal?: AbortSignal;
11
+ }
12
+ export interface CallResult {
13
+ readonly text: string;
14
+ }
15
+ export declare function runProviderTextGeneration(modelId: string, prompt: string, callOpts: CallOpts): Promise<CallResult>;
16
+ /**
17
+ * Helper used by worker-proxy conformance tests to drive a streaming
18
+ * text-generation run-fn end-to-end against the dispatched provider. Yields
19
+ * the raw `StreamEvent` objects so callers can assert on the event sequence;
20
+ * use {@link collectStream} when only the final output matters.
21
+ */
22
+ export declare function streamProviderTextGeneration(modelId: string, prompt: string, callOpts: CallOpts): AsyncGenerator<unknown, void, void>;
23
+ export { collectStream };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WorkerProxyBoundaryOpts } from "./types";
7
+ export declare function browserOnlyStubBlock(opts: WorkerProxyBoundaryOpts): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WorkerProxyBoundaryOpts } from "./types";
7
+ export declare function runWorkerProxyBoundary(opts: WorkerProxyBoundaryOpts): void;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, ConformanceHandle } from "../ai-provider/types";
7
+ export interface WorkerProxyBoundaryOpts {
8
+ readonly name: string;
9
+ readonly skip?: boolean;
10
+ readonly timeout: number;
11
+ /**
12
+ * Returns a handle whose `register()` installs the worker as the active
13
+ * route for every model named in `opts.models`. The boundary assertions
14
+ * dispatch via `getAiProviderRegistry()` / `textGeneration()` and rely on
15
+ * this to ensure traffic actually crosses the worker postMessage boundary
16
+ * — without it the assertions would pass against an inline provider for
17
+ * the wrong reason. Adapter shims must guarantee this invariant.
18
+ */
19
+ readonly factory: () => Promise<ConformanceHandle>;
20
+ readonly capabilities: WorkerProxyCapabilities;
21
+ readonly models: WorkerProxyModels;
22
+ readonly fixture?: Partial<ConformanceFixture>;
23
+ /**
24
+ * Names of boundary assertions that are currently broken in this adapter.
25
+ * Each named assertion is wrapped in `it.fails` instead of `it`.
26
+ *
27
+ * Known names:
28
+ * "boundary.disposeTerminatesWorker"
29
+ * "boundary.errorPropagation"
30
+ * "boundary.backlogOrdering"
31
+ */
32
+ readonly expectedFailures?: ReadonlyArray<string>;
33
+ }
34
+ export interface WorkerProxyCapabilities {
35
+ /** When true, the entire boundary block is replaced with a single skipped
36
+ * test logging "<name>: requires browser test runner". */
37
+ readonly browserOnly: boolean;
38
+ /** When false, only the basic "rejection surfaces on the main thread"
39
+ * assertion runs. When true, additionally asserts that the worker-thrown
40
+ * `Error.name` and `Error.message` round-trip across the postMessage
41
+ * boundary intact. Default true. */
42
+ readonly errorPropagation: boolean;
43
+ }
44
+ export interface WorkerProxyModels {
45
+ readonly textGeneration?: string;
46
+ readonly toolCalling?: string;
47
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * Parity boundary for an adapter registered through a worker: the inline
8
+ * assertions must still hold across `postMessage`.
9
+ */
10
+ export * from "./worker-proxy/browserOnlyStub";
11
+ export * from "./worker-proxy/runWorkerProxyBoundary";
12
+ export * from "./worker-proxy/types";
13
+ export * from "./worker-proxy/assertions/backlogOrdering";
14
+ export * from "./worker-proxy/assertions/disposeTerminatesWorker";
15
+ export * from "./worker-proxy/assertions/errorPropagation";
16
+ export * from "./worker-proxy/assertions/providerCallHelpers";