@dxos/plugin-magazine 0.9.1-staging.ee54ba693a → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/MagazinePlugin.mjs +36 -0
- package/dist/lib/MagazinePlugin.mjs.map +1 -0
- package/dist/lib/MagazinePlugin.workerd.mjs +26 -0
- package/dist/lib/MagazinePlugin.workerd.mjs.map +1 -0
- package/dist/lib/atoms.mjs +175 -0
- package/dist/lib/atoms.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +12 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-FeedArticle.mjs +70 -0
- package/dist/lib/chunk-FeedArticle.mjs.map +1 -0
- package/dist/lib/chunk-FeedProperties.mjs +78 -0
- package/dist/lib/chunk-FeedProperties.mjs.map +1 -0
- package/dist/lib/chunk-MagazineArticle.mjs +267 -0
- package/dist/lib/chunk-MagazineArticle.mjs.map +1 -0
- package/dist/lib/chunk-PostArticle.mjs +174 -0
- package/dist/lib/chunk-PostArticle.mjs.map +1 -0
- package/dist/lib/chunk-PostCard.mjs +62 -0
- package/dist/lib/chunk-PostCard.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +91 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-clear-magazine.mjs +37 -0
- package/dist/lib/chunk-clear-magazine.mjs.map +1 -0
- package/dist/lib/chunk-create-object.mjs +59 -0
- package/dist/lib/chunk-create-object.mjs.map +1 -0
- package/dist/lib/chunk-curate-magazine.mjs +164 -0
- package/dist/lib/chunk-curate-magazine.mjs.map +1 -0
- package/dist/lib/chunk-date.mjs +25 -0
- package/dist/lib/chunk-date.mjs.map +1 -0
- package/dist/lib/chunk-fetch-article-content.mjs +26 -0
- package/dist/lib/chunk-fetch-article-content.mjs.map +1 -0
- package/dist/lib/chunk-load-post-content.mjs +57 -0
- package/dist/lib/chunk-load-post-content.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-JFPR6OV4.mjs → chunk-meta.mjs} +19 -26
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +13 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-paths.mjs +8 -0
- package/dist/lib/chunk-paths.mjs.map +1 -0
- package/dist/lib/chunk-post-content.mjs +14 -0
- package/dist/lib/chunk-post-content.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +60 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-routine-templates.mjs +52 -0
- package/dist/lib/chunk-routine-templates.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +12 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-sources.mjs +576 -0
- package/dist/lib/chunk-sources.mjs.map +1 -0
- package/dist/lib/chunk-sync-feed.mjs +86 -0
- package/dist/lib/chunk-sync-feed.mjs.map +1 -0
- package/dist/lib/chunk-text.mjs +52 -0
- package/dist/lib/chunk-text.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +607 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/components.mjs +323 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +11 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/index.mjs +3 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/plugin.workerd.mjs +3 -0
- package/dist/lib/{neutral/skills/index.mjs → skills.mjs} +15 -28
- package/dist/lib/skills.mjs.map +1 -0
- package/dist/lib/testing.mjs +71 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +74 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/MagazinePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts +0 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/routine-templates.d.ts +1 -1
- package/dist/types/src/components/PostContent/PostContent.d.ts +1 -13
- package/dist/types/src/components/PostContent/PostContent.d.ts.map +1 -1
- package/dist/types/src/components/PostContent/dedupe-images.d.ts +13 -0
- package/dist/types/src/components/PostContent/dedupe-images.d.ts.map +1 -0
- package/dist/types/src/components/PostContent/index.d.ts +1 -0
- package/dist/types/src/components/PostContent/index.d.ts.map +1 -1
- package/dist/types/src/components/PostStack/PostStack.d.ts +1 -1
- package/dist/types/src/components/PostStack/PostStack.d.ts.map +1 -1
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts +1 -1
- package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts.map +1 -1
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts +4 -1
- package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts.map +1 -1
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts +4 -1
- package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts +4 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts +4 -1
- package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts.map +1 -1
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts +4 -8
- package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts +4 -1
- package/dist/types/src/containers/PostArticle/PostArticle.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts +1 -1
- package/dist/types/src/containers/PostArticle/PostToolbar.d.ts.map +1 -1
- package/dist/types/src/containers/PostCard/PostCard.d.ts +4 -6
- package/dist/types/src/containers/PostCard/PostCard.d.ts.map +1 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts +4 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts.map +1 -1
- package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts.map +1 -1
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts +1 -0
- package/dist/types/src/stories/ArticleExtractor.stories.d.ts.map +1 -1
- package/dist/types/src/stories/MagazineCurate.stories.d.ts.map +1 -1
- package/dist/types/src/templates/magazine-curation.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -1
- package/package.json +57 -60
- package/src/MagazinePlugin.tsx +0 -3
- package/src/atoms/atoms.test.ts +5 -4
- package/src/capabilities/app-graph-builder.ts +8 -6
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/{react-surface.tsx → react-surface.ts} +10 -12
- package/src/components/PostContent/PostContent.test.ts +1 -1
- package/src/components/PostContent/PostContent.tsx +1 -41
- package/src/components/PostContent/dedupe-images.ts +48 -0
- package/src/components/PostContent/index.ts +1 -0
- package/src/containers/FeedArticle/FeedArticle.stories.tsx +2 -2
- package/src/containers/FeedArticle/FeedArticle.tsx +4 -2
- package/src/containers/FeedProperties/FeedProperties.tsx +6 -4
- package/src/containers/MagazineArticle/MagazineArticle.stories.tsx +2 -1
- package/src/containers/MagazineArticle/MagazineArticle.tsx +8 -6
- package/src/containers/MagazineArticle/MagazineTile.tsx +2 -0
- package/src/containers/MagazineArticle/useToolbar.tsx +2 -0
- package/src/containers/PostArticle/PostArticle.stories.tsx +2 -1
- package/src/containers/PostArticle/PostArticle.tsx +6 -3
- package/src/containers/PostArticle/PostToolbar.tsx +1 -1
- package/src/containers/PostCard/PostCard.tsx +3 -1
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.tsx +2 -1
- package/src/containers/SubscriptionsArticle/SubscriptionsArticle.tsx +5 -3
- package/src/operations/curate-magazine.test.ts +108 -4
- package/src/operations/sync-feed.test.ts +1 -1
- package/src/operations/sync-feed.ts +1 -1
- package/src/paths.ts +3 -3
- package/src/stories/ArticleExtractor.stories.tsx +1 -1
- package/src/stories/MagazineCurate.stories.tsx +3 -2
- package/src/templates/magazine-curation.ts +3 -2
- package/src/types/Magazine.test.ts +1 -1
- package/src/types/Subscription.ts +1 -1
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs +0 -90
- package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs.map +0 -7
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs +0 -97
- package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs.map +0 -7
- package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs +0 -325
- package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs.map +0 -7
- package/dist/lib/neutral/MagazinePlugin.mjs +0 -62
- package/dist/lib/neutral/MagazinePlugin.mjs.map +0 -7
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs +0 -12
- package/dist/lib/neutral/MagazinePlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs +0 -230
- package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs.map +0 -7
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs +0 -60
- package/dist/lib/neutral/PostCard-VDGN7BBA.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs +0 -121
- package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -21
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs +0 -12
- package/dist/lib/neutral/chunk-3K4AQKBZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs +0 -591
- package/dist/lib/neutral/chunk-AFPBWBTK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-APQRTYT3.mjs +0 -57
- package/dist/lib/neutral/chunk-APQRTYT3.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GU725ZF4.mjs +0 -11
- package/dist/lib/neutral/chunk-GU725ZF4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JFPR6OV4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs +0 -36
- package/dist/lib/neutral/chunk-KTYLUOUG.mjs.map +0 -7
- package/dist/lib/neutral/chunk-LFSQMLPK.mjs +0 -8
- package/dist/lib/neutral/chunk-LFSQMLPK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs +0 -14
- package/dist/lib/neutral/chunk-MBPX7RPI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs +0 -624
- package/dist/lib/neutral/chunk-OYCDRSWB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs +0 -28
- package/dist/lib/neutral/chunk-SAWKLGJU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XCNCK47N.mjs +0 -15
- package/dist/lib/neutral/chunk-XCNCK47N.mjs.map +0 -7
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs +0 -59
- package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -338
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -17
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs +0 -98
- package/dist/lib/neutral/create-object-SYZMRR4H.mjs.map +0 -7
- package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs +0 -184
- package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs.map +0 -7
- package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs +0 -31
- package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -18
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs +0 -65
- package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs +0 -18
- package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs +0 -8
- package/dist/lib/neutral/operation-handler-JE3743BU.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/plugin.workerd.mjs +0 -16
- package/dist/lib/neutral/plugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs +0 -60
- package/dist/lib/neutral/react-surface-TZESAMG2.mjs.map +0 -7
- package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs +0 -52
- package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs.map +0 -7
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs +0 -8
- package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs.map +0 -7
- package/dist/lib/neutral/skills/index.mjs.map +0 -7
- package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs +0 -99
- package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -81
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -14
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts +0 -2
- package/dist/types/src/operations/curate-magazine.skill.test.d.ts.map +0 -1
- package/src/capabilities/navigation-resolver.ts +0 -21
- package/src/operations/curate-magazine.skill.conversations.json +0 -1
- package/src/operations/curate-magazine.skill.test.ts +0 -167
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
browserCorsProxy,
|
|
3
|
-
fetchRss,
|
|
4
|
-
fetchStandardSite
|
|
5
|
-
} from "./chunk-AFPBWBTK.mjs";
|
|
6
|
-
import {
|
|
7
|
-
FeedOperation_exports,
|
|
8
|
-
Subscription_exports
|
|
9
|
-
} from "./chunk-OYCDRSWB.mjs";
|
|
10
|
-
import "./chunk-APQRTYT3.mjs";
|
|
11
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
12
|
-
|
|
13
|
-
// src/operations/sync-feed.ts
|
|
14
|
-
import * as Effect from "effect/Effect";
|
|
15
|
-
import { Operation } from "@dxos/compute";
|
|
16
|
-
import { Database, Feed, Filter, Obj, Ref } from "@dxos/echo";
|
|
17
|
-
import { invariant } from "@dxos/invariant";
|
|
18
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-magazine/src/operations/sync-feed.ts";
|
|
19
|
-
var postKey = (post) => post.guid ?? post.link;
|
|
20
|
-
var getFetcher = (type) => {
|
|
21
|
-
switch (type) {
|
|
22
|
-
case "standard-site":
|
|
23
|
-
return fetchStandardSite;
|
|
24
|
-
case "rss":
|
|
25
|
-
default:
|
|
26
|
-
return fetchRss;
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var handler = FeedOperation_exports.SyncFeed.pipe(Operation.withHandler(Effect.fnUntraced(function* ({ feed }) {
|
|
30
|
-
const subscriptionFeed = yield* Database.load(feed);
|
|
31
|
-
const url = subscriptionFeed.url;
|
|
32
|
-
invariant(url, "Feed URL is required.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 23, S: this, A: ["url", "'Feed URL is required.'"] });
|
|
33
|
-
const echoFeed = yield* Database.load(subscriptionFeed.feed);
|
|
34
|
-
invariant(echoFeed, "Backing ECHO feed not found.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 25, S: this, A: ["echoFeed", "'Backing ECHO feed not found.'"] });
|
|
35
|
-
invariant(Feed.getQueueUri(echoFeed), "Feed not stored in a space.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 26, S: this, A: ["Feed.getQueueUri(echoFeed)", "'Feed not stored in a space.'"] });
|
|
36
|
-
const fetcher = getFetcher(subscriptionFeed.type);
|
|
37
|
-
const { feed: feedMeta, posts } = yield* fetcher(url, {
|
|
38
|
-
corsProxy: browserCorsProxy()
|
|
39
|
-
});
|
|
40
|
-
yield* Feed.sync(echoFeed, {
|
|
41
|
-
shouldPush: false
|
|
42
|
-
});
|
|
43
|
-
const existing = yield* Feed.query(echoFeed, Filter.type(Subscription_exports.Post)).run;
|
|
44
|
-
const seenKeys = /* @__PURE__ */ new Set();
|
|
45
|
-
for (const post of existing) {
|
|
46
|
-
const key = postKey(post);
|
|
47
|
-
if (key) {
|
|
48
|
-
seenKeys.add(key);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const newPosts = [];
|
|
52
|
-
for (const post of posts) {
|
|
53
|
-
const key = postKey(post);
|
|
54
|
-
if (key && seenKeys.has(key)) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (key) {
|
|
58
|
-
seenKeys.add(key);
|
|
59
|
-
}
|
|
60
|
-
newPosts.push(post);
|
|
61
|
-
}
|
|
62
|
-
if (newPosts.length > 0) {
|
|
63
|
-
const feedRef = Ref.make(subscriptionFeed);
|
|
64
|
-
const postObjects = newPosts.map((post) => Obj.make(Subscription_exports.Post, {
|
|
65
|
-
source: feedRef,
|
|
66
|
-
title: post.title,
|
|
67
|
-
link: post.link,
|
|
68
|
-
description: post.description,
|
|
69
|
-
// Persist the body so Standard.site articles render offline (see `load-post-content`);
|
|
70
|
-
// RSS `content:encoded` rides along but its fetch path is unchanged.
|
|
71
|
-
content: post.content,
|
|
72
|
-
author: post.author,
|
|
73
|
-
published: post.published,
|
|
74
|
-
guid: post.guid
|
|
75
|
-
}));
|
|
76
|
-
yield* Feed.append(echoFeed, postObjects);
|
|
77
|
-
const newestGuid = posts[0]?.guid;
|
|
78
|
-
if (newestGuid) {
|
|
79
|
-
Obj.update(subscriptionFeed, (subscriptionFeed2) => {
|
|
80
|
-
subscriptionFeed2.cursor = newestGuid;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
if (feedMeta.name && !subscriptionFeed.name) {
|
|
84
|
-
Obj.update(subscriptionFeed, (subscriptionFeed2) => {
|
|
85
|
-
subscriptionFeed2.name = feedMeta.name;
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
if (feedMeta.description && !subscriptionFeed.description) {
|
|
89
|
-
Obj.update(subscriptionFeed, (subscriptionFeed2) => {
|
|
90
|
-
subscriptionFeed2.description = feedMeta.description;
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
})));
|
|
95
|
-
var sync_feed_default = handler;
|
|
96
|
-
export {
|
|
97
|
-
sync_feed_default as default
|
|
98
|
-
};
|
|
99
|
-
//# sourceMappingURL=sync-feed-SDXYF7HU.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/operations/sync-feed.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Operation } from '@dxos/compute';\nimport { Database, Feed, Filter, Obj, Ref } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\n\nimport { FeedOperation, Subscription } from '../types';\nimport { type FeedFetcher, browserCorsProxy, fetchRss, fetchStandardSite } from './sources';\n\n/** Stable dedup key for a {@link Subscription.Post}. Both fields are optional, but every current fetcher populates `guid` (RSS falls back to `link`, Standard.site uses the record AT-URI). */\nconst postKey = (post: { guid?: string; link?: string }): string | undefined => post.guid ?? post.link;\n\n/** Resolves the appropriate fetcher for the given feed type. */\nconst getFetcher = (type: Subscription.FeedType | undefined): FeedFetcher => {\n switch (type) {\n case 'standard-site':\n return fetchStandardSite;\n case 'rss':\n default:\n return fetchRss;\n }\n};\n\nconst handler: Operation.WithHandler<typeof FeedOperation.SyncFeed> = FeedOperation.SyncFeed.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ feed }) {\n const subscriptionFeed = yield* Database.load(feed);\n const url = subscriptionFeed.url;\n invariant(url, 'Feed URL is required.');\n const echoFeed = yield* Database.load(subscriptionFeed.feed);\n invariant(echoFeed, 'Backing ECHO feed not found.');\n invariant(Feed.getQueueUri(echoFeed), 'Feed not stored in a space.');\n\n const fetcher = getFetcher(subscriptionFeed.type);\n const { feed: feedMeta, posts } = yield* fetcher(url, { corsProxy: browserCorsProxy() });\n\n // Dedup against existing posts already in the backing queue. The\n // `cursor` field on the subscription was previously used as a single-guid\n // filter, but RSS feeds re-serve the same items across polls — filtering\n // out only the cursor's own guid let every other previously-synced post\n // re-pass the filter and re-append on each sync. Key-based dedup against\n // the queue is the source of truth and tolerant of out-of-order or\n // rotated-off-the-window upstream responses.\n //\n // The dedup key is `guid ?? link`: `Post.guid` is optional in the schema,\n // and while every current fetcher populates it (RSS falls back to `link`,\n // Standard.site uses the record AT-URI), a future fetcher or malformed item\n // could omit it. Falling back to `link` keeps such items dedup-able. Items\n // with neither field cannot be deduplicated and will sync as new every\n // time — that's an upstream data quality issue with no clean recovery.\n //\n // Pull the backing queue before reading existing posts: this handler runs in a\n // freshly-spawned process whose local queue replica may not have the blocks yet. Without\n // this, the query returns an empty set, `seenKeys` is empty, and every fetched item\n // re-appends — duplicating the whole feed on a cold sync.\n yield* Feed.sync(echoFeed, { shouldPush: false });\n const existing = yield* Feed.query(echoFeed, Filter.type(Subscription.Post)).run;\n const seenKeys = new Set<string>();\n for (const post of existing) {\n const key = postKey(post);\n if (key) {\n seenKeys.add(key);\n }\n }\n const newPosts: typeof posts = [];\n for (const post of posts) {\n const key = postKey(post);\n // Within-batch dedup: if the upstream serves the same item twice in one\n // response, only the first occurrence is appended.\n if (key && seenKeys.has(key)) {\n continue;\n }\n if (key) {\n seenKeys.add(key);\n }\n newPosts.push(post);\n }\n\n // Append new posts to the ECHO feed.\n // NOTE: The `Subscription.Subscription.keep` bound is currently NOT enforced\n // here via `Feed.remove()`. Doing so wipes the underlying queue's\n // `_objectCache` for the deleted posts, but those same Post objects\n // persist in `space.db` (they were added there when first curated\n // into a Magazine via `createRef` → `database.add`). On the next\n // sync/curate, `Feed.query(...).run` returns fresh proxies for the\n // kept items, and any magazine refs to *deleted* posts now\n // reference proxies whose `_internals.database` link is unset —\n // `createRef` then tries to re-add them, hitting the\n // `!_objects.has(core.id)` invariant in `EntityManager.addCore`.\n // Until feed/db lifecycle is reworked we leave the feed unbounded;\n // the `Magazine.keep` bound (enforced in\n // `MagazineArticle.handleCurate`) prevents the visible list from\n // growing unboundedly.\n if (newPosts.length > 0) {\n const feedRef = Ref.make(subscriptionFeed);\n const postObjects = newPosts.map((post) =>\n Obj.make(Subscription.Post, {\n source: feedRef,\n title: post.title,\n link: post.link,\n description: post.description,\n // Persist the body so Standard.site articles render offline (see `load-post-content`);\n // RSS `content:encoded` rides along but its fetch path is unchanged.\n content: post.content,\n author: post.author,\n published: post.published,\n guid: post.guid,\n }),\n );\n yield* Feed.append(echoFeed, postObjects);\n\n // Advance cursor to the newest post.\n const newestGuid = posts[0]?.guid;\n if (newestGuid) {\n Obj.update(subscriptionFeed, (subscriptionFeed) => {\n subscriptionFeed.cursor = newestGuid;\n });\n }\n\n // Update feed metadata from channel if not already set.\n if (feedMeta.name && !subscriptionFeed.name) {\n Obj.update(subscriptionFeed, (subscriptionFeed) => {\n subscriptionFeed.name = feedMeta.name;\n });\n }\n if (feedMeta.description && !subscriptionFeed.description) {\n Obj.update(subscriptionFeed, (subscriptionFeed) => {\n subscriptionFeed.description = feedMeta.description;\n });\n }\n }\n }),\n ),\n);\n\nexport default handler;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,iBAAiB;AAC1B,SAASC,UAAUC,MAAMC,QAAQC,KAAKC,WAAW;AACjD,SAASC,iBAAiB;AAK1B,IAAA,eAAA;AAKUC,IAAAA,UAAAA,CAAAA,SAAAA,KAAAA,QAAAA,KAAAA;AACD,IAAA,aAAA,CAAA,SAAA;gBACH;IACF,KAAK;AACL,aAAA;SACE;IACJ;AACF,aAAA;EAEA;;IAIM,UAAYC,sBAAAA,SAAoB,KAAA,UAAA,YAAA,kBAAA,WAAA,EAAA,KAAA,GAAA;AAChCC,QAAAA,mBAAe,OAAA,SAAA,KAAA,IAAA;AACf,QAAMC,MAAAA,iBAAkBC;AACxBF,YAAUC,KAAAA,yBAAU,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,OAAA,yBAAA,EAAA,CAAA;AACpBD,QAAAA,WAAeG,OAAAA,SAAYF,KAAW,iBAAA,IAAA;AAEtC,YAAMG,UAAUC,gCAAgC,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,YAAA,gCAAA,EAAA,CAAA;AAChD,YAAQC,KAAMC,YAAUC,QAAU,GAAA,+BAAoB,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,8BAAA,+BAAA,EAAA,CAAA;QAAEC,UAAWC,WAAAA,iBAAAA,IAAAA;AAAmB,QAAA,EAAA,MAAA,UAAA,MAAA,IAAA,OAAA,QAAA,KAAA;IAEtF,WAAA,iBAAA;EACA,CAAA;AAkB+C,SAAA,KAAA,KAAA,UAAA;IAC/C,YAAMC;EACN,CAAA;AACA,QAAK,WAAMC,OAAQD,KAAU,MAAA,UAAA,OAAA,KAAA,qBAAA,IAAA,CAAA,EAAA;QAC3B,WAAYE,oBAAAA,IAAQD;aAChBE,QAAK,UAAA;UACPC,MAAAA,QAAaD,IAAAA;AACf,QAAA,KAAA;AACF,eAAA,IAAA,GAAA;IACA;EACA;QACE,WAAYD,CAAAA;aACZ,QAAA,OAAA;AACA,UAAA,MAAA,QAAA,IAAA;AAGA,QAAA,OAAA,SAAA,IAAA,GAAA,GAAA;AACIC;;AAEJ,QAAA,KAAA;AACAE,eAAa,IAACJ,GAAAA;IAChB;AAEA,aAAA,KAAA,IAAA;EACA;MAgBE,SAAMK,SAAAA,GAAcD;oBAERE,IAAAA,KAAAA,gBAAAA;wBACIC,SAAK,IAAA,CAAA,SAAA,IAAA,KAAA,qBAAA,MAAA;MACjBC,QAAMR;MACNS,OAAAA,KAAAA;MACA,MAAA,KAAA;MACA,aAAA,KAAA;;;MAGAC,SAAAA,KAAWV;MACXW,QAAMX,KAAKW;MACb,WAAA,KAAA;MAEKC,MAAKC,KAAOxB;IAEnB,CAAA,CAAA;AACA,WAAMyB,KAAAA,OAAalB,UAAUe,WAAAA;UAE3BI,aAAW5B,MAAAA,CAAAA,GAAAA;oBACTA;AACF,UAAA,OAAA,kBAAA,CAAAA,sBAAA;AACF,QAAAA,kBAAA,SAAA;MAEA,CAAA;IACA;iBAEIA,QAAAA,CAAAA,iBAAwBQ,MAAa;AACvC,UAAA,OAAA,kBAAA,CAAAR,sBAAA;AACF,QAAAA,kBAAA,OAAA,SAAA;MACIQ,CAAAA;;iBAEAR,eAAiBsB,CAAAA,iBAAcd,aAAoB;AACrD,UAAA,OAAA,kBAAA,CAAAR,sBAAA;AACF,QAAAA,kBAAA,cAAA,SAAA;MACF,CAAA;IACF;EAIJ;;;",
|
|
6
|
-
"names": ["Effect", "Operation", "Database", "Feed", "Filter", "Obj", "Ref", "invariant", "type", "subscriptionFeed", "invariant", "echoFeed", "Database", "getQueueUri", "fetcher", "getFetcher", "feed", "feedMeta", "posts", "corsProxy", "browserCorsProxy", "existing", "post", "postKey", "key", "seenKeys", "newPosts", "postObjects", "feedRef", "title", "link", "description", "published", "guid", "Feed", "append", "newestGuid", "Obj"]
|
|
7
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import "./chunk-J5LGTIGS.mjs";
|
|
2
|
-
|
|
3
|
-
// src/translations.ts
|
|
4
|
-
import { Type } from "@dxos/echo";
|
|
5
|
-
import { translations as formTranslations } from "@dxos/react-ui-form/translations";
|
|
6
|
-
import { meta } from "#meta";
|
|
7
|
-
import { Magazine, Subscription } from "#types";
|
|
8
|
-
var translations = [
|
|
9
|
-
...formTranslations,
|
|
10
|
-
{
|
|
11
|
-
"en-US": {
|
|
12
|
-
[Type.getTypename(Subscription.Subscription)]: {
|
|
13
|
-
"typename.label": "Feed",
|
|
14
|
-
"typename.label_zero": "Feeds",
|
|
15
|
-
"typename.label_one": "Feed",
|
|
16
|
-
"typename.label_other": "Feeds",
|
|
17
|
-
"object-name.placeholder": "New feed",
|
|
18
|
-
"add-object.label": "Add feed",
|
|
19
|
-
"rename-object.label": "Rename feed",
|
|
20
|
-
"delete-object.label": "Delete feed",
|
|
21
|
-
"object-deleted.label": "Feed deleted"
|
|
22
|
-
},
|
|
23
|
-
[Type.getTypename(Subscription.Post)]: {
|
|
24
|
-
"typename.label": "Post",
|
|
25
|
-
"typename.label_zero": "Posts",
|
|
26
|
-
"typename.label_one": "Post",
|
|
27
|
-
"typename.label_other": "Posts",
|
|
28
|
-
"post-title.placeholder": "Untitled"
|
|
29
|
-
},
|
|
30
|
-
[Type.getTypename(Magazine.Magazine)]: {
|
|
31
|
-
"typename.label": "Magazine",
|
|
32
|
-
"typename.label_zero": "Magazines",
|
|
33
|
-
"typename.label_one": "Magazine",
|
|
34
|
-
"typename.label_other": "Magazines",
|
|
35
|
-
"object-name.placeholder": "New magazine",
|
|
36
|
-
"add-object.label": "Add magazine",
|
|
37
|
-
"rename-object.label": "Rename magazine",
|
|
38
|
-
"delete-object.label": "Delete magazine",
|
|
39
|
-
"object-deleted.label": "Magazine deleted"
|
|
40
|
-
},
|
|
41
|
-
[meta.profile.key]: {
|
|
42
|
-
"plugin.name": "Feed",
|
|
43
|
-
"empty-feed.message": "No posts yet",
|
|
44
|
-
"feed-companion.label": "Feed",
|
|
45
|
-
"sync-feed.label": "Sync feed",
|
|
46
|
-
"sync-feed-error.title": "Failed to sync feed",
|
|
47
|
-
"feed-sync.label": "Feed Sync",
|
|
48
|
-
"view-trigger.label": "View trigger",
|
|
49
|
-
"add-feed.label": "Add feed",
|
|
50
|
-
"curate.label": "Curate",
|
|
51
|
-
"clear-magazine.label": "Clear (preserves starred)",
|
|
52
|
-
"refreshing-magazine.label": "Refreshing magazine...",
|
|
53
|
-
"no-feeds.label": "Add at least one feed first",
|
|
54
|
-
"empty-magazine.message": "No articles yet.",
|
|
55
|
-
"curate-error.message": "Failed to curate magazine.",
|
|
56
|
-
"clear-error.message": "Failed to clear magazine.",
|
|
57
|
-
"refresh-content-error.message": "Failed to refresh content.",
|
|
58
|
-
"post-companion.label": "Post",
|
|
59
|
-
"post-title.placeholder": "Untitled",
|
|
60
|
-
"open-original.label": "Open original",
|
|
61
|
-
"mark-unread.label": "Mark as unread",
|
|
62
|
-
"refresh-content.label": "Refresh content",
|
|
63
|
-
"refresh-content-pending.label": "Refreshing\u2026",
|
|
64
|
-
"archive-post.label": "Archive",
|
|
65
|
-
"unarchive-post.label": "Unarchive",
|
|
66
|
-
"star-post.label": "Star",
|
|
67
|
-
"unstar-post.label": "Unstar",
|
|
68
|
-
"sort-by-date.label": "Sort by date",
|
|
69
|
-
"sort-by-rank.label": "Sort by rank",
|
|
70
|
-
"view-filter.label": "Filter posts",
|
|
71
|
-
"show-archived.label": "Show archived",
|
|
72
|
-
"only-starred.label": "Show starred only",
|
|
73
|
-
"close.label": "Close"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
];
|
|
78
|
-
export {
|
|
79
|
-
translations
|
|
80
|
-
};
|
|
81
|
-
//# sourceMappingURL=translations.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/translations.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Type } from '@dxos/echo';\nimport { type Resource } from '@dxos/react-ui';\nimport { translations as formTranslations } from '@dxos/react-ui-form/translations';\n\nimport { meta } from '#meta';\nimport { Magazine, Subscription } from '#types';\n\nexport const translations = [\n ...formTranslations,\n {\n 'en-US': {\n [Type.getTypename(Subscription.Subscription)]: {\n 'typename.label': 'Feed',\n 'typename.label_zero': 'Feeds',\n 'typename.label_one': 'Feed',\n 'typename.label_other': 'Feeds',\n 'object-name.placeholder': 'New feed',\n 'add-object.label': 'Add feed',\n 'rename-object.label': 'Rename feed',\n 'delete-object.label': 'Delete feed',\n 'object-deleted.label': 'Feed deleted',\n },\n [Type.getTypename(Subscription.Post)]: {\n 'typename.label': 'Post',\n 'typename.label_zero': 'Posts',\n 'typename.label_one': 'Post',\n 'typename.label_other': 'Posts',\n 'post-title.placeholder': 'Untitled',\n },\n [Type.getTypename(Magazine.Magazine)]: {\n 'typename.label': 'Magazine',\n 'typename.label_zero': 'Magazines',\n 'typename.label_one': 'Magazine',\n 'typename.label_other': 'Magazines',\n 'object-name.placeholder': 'New magazine',\n 'add-object.label': 'Add magazine',\n 'rename-object.label': 'Rename magazine',\n 'delete-object.label': 'Delete magazine',\n 'object-deleted.label': 'Magazine deleted',\n },\n [meta.profile.key]: {\n 'plugin.name': 'Feed',\n 'empty-feed.message': 'No posts yet',\n 'feed-companion.label': 'Feed',\n 'sync-feed.label': 'Sync feed',\n 'sync-feed-error.title': 'Failed to sync feed',\n 'feed-sync.label': 'Feed Sync',\n 'view-trigger.label': 'View trigger',\n 'add-feed.label': 'Add feed',\n 'curate.label': 'Curate',\n 'clear-magazine.label': 'Clear (preserves starred)',\n 'refreshing-magazine.label': 'Refreshing magazine...',\n 'no-feeds.label': 'Add at least one feed first',\n 'empty-magazine.message': 'No articles yet.',\n 'curate-error.message': 'Failed to curate magazine.',\n 'clear-error.message': 'Failed to clear magazine.',\n 'refresh-content-error.message': 'Failed to refresh content.',\n 'post-companion.label': 'Post',\n 'post-title.placeholder': 'Untitled',\n 'open-original.label': 'Open original',\n 'mark-unread.label': 'Mark as unread',\n 'refresh-content.label': 'Refresh content',\n 'refresh-content-pending.label': 'Refreshing…',\n 'archive-post.label': 'Archive',\n 'unarchive-post.label': 'Unarchive',\n 'star-post.label': 'Star',\n 'unstar-post.label': 'Unstar',\n 'sort-by-date.label': 'Sort by date',\n 'sort-by-rank.label': 'Sort by rank',\n 'view-filter.label': 'Filter posts',\n 'show-archived.label': 'Show archived',\n 'only-starred.label': 'Show starred only',\n 'close.label': 'Close',\n },\n },\n },\n] as const satisfies Resource[];\n"],
|
|
5
|
-
"mappings": ";;;AAIA,SAASA,YAAY;AAErB,SAASC,gBAAgBC,wBAAwB;AAEjD,SAASC,YAAY;AACrB,SAASC,UAAUC,oBAAoB;AAEhC,IAAMJ,eAAe;KACvBC;EACH;IACE,SAAS;MACP,CAACF,KAAKM,YAAYD,aAAaA,YAAY,CAAA,GAAI;QAC7C,kBAAkB;QAClB,uBAAuB;QACvB,sBAAsB;QACtB,wBAAwB;QACxB,2BAA2B;QAC3B,oBAAoB;QACpB,uBAAuB;QACvB,uBAAuB;QACvB,wBAAwB;MAC1B;MACA,CAACL,KAAKM,YAAYD,aAAaE,IAAI,CAAA,GAAI;QACrC,kBAAkB;QAClB,uBAAuB;QACvB,sBAAsB;QACtB,wBAAwB;QACxB,0BAA0B;MAC5B;MACA,CAACP,KAAKM,YAAYF,SAASA,QAAQ,CAAA,GAAI;QACrC,kBAAkB;QAClB,uBAAuB;QACvB,sBAAsB;QACtB,wBAAwB;QACxB,2BAA2B;QAC3B,oBAAoB;QACpB,uBAAuB;QACvB,uBAAuB;QACvB,wBAAwB;MAC1B;MACA,CAACD,KAAKK,QAAQC,GAAG,GAAG;QAClB,eAAe;QACf,sBAAsB;QACtB,wBAAwB;QACxB,mBAAmB;QACnB,yBAAyB;QACzB,mBAAmB;QACnB,sBAAsB;QACtB,kBAAkB;QAClB,gBAAgB;QAChB,wBAAwB;QACxB,6BAA6B;QAC7B,kBAAkB;QAClB,0BAA0B;QAC1B,wBAAwB;QACxB,uBAAuB;QACvB,iCAAiC;QACjC,wBAAwB;QACxB,0BAA0B;QAC1B,uBAAuB;QACvB,qBAAqB;QACrB,yBAAyB;QACzB,iCAAiC;QACjC,sBAAsB;QACtB,wBAAwB;QACxB,mBAAmB;QACnB,qBAAqB;QACrB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,uBAAuB;QACvB,sBAAsB;QACtB,eAAe;MACjB;IACF;EACF;;",
|
|
6
|
-
"names": ["Type", "translations", "formTranslations", "meta", "Magazine", "Subscription", "getTypename", "Post", "profile", "key"]
|
|
7
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CreateSubscription_exports,
|
|
3
|
-
FeedOperation_exports,
|
|
4
|
-
Magazine_exports,
|
|
5
|
-
Subscription_exports
|
|
6
|
-
} from "../chunk-OYCDRSWB.mjs";
|
|
7
|
-
import "../chunk-J5LGTIGS.mjs";
|
|
8
|
-
export {
|
|
9
|
-
CreateSubscription_exports as CreateSubscription,
|
|
10
|
-
FeedOperation_exports as FeedOperation,
|
|
11
|
-
Magazine_exports as Magazine,
|
|
12
|
-
Subscription_exports as Subscription
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-resolver.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/navigation-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"curate-magazine.skill.test.d.ts","sourceRoot":"","sources":["../../../../src/operations/curate-magazine.skill.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import * as Effect from 'effect/Effect';
|
|
6
|
-
|
|
7
|
-
import { Capability } from '@dxos/app-framework';
|
|
8
|
-
import { AppCapabilities, Paths, TypeSection } from '@dxos/app-toolkit';
|
|
9
|
-
|
|
10
|
-
import { Magazine } from '#types';
|
|
11
|
-
|
|
12
|
-
export default Capability.makeModule(
|
|
13
|
-
Effect.fnUntraced(function* () {
|
|
14
|
-
return [
|
|
15
|
-
Capability.contributes(
|
|
16
|
-
AppCapabilities.NavigationPathResolver,
|
|
17
|
-
TypeSection.createTypeSectionPathResolver(Magazine.Magazine, { groupId: Paths.GroupSegments.content }),
|
|
18
|
-
),
|
|
19
|
-
];
|
|
20
|
-
}),
|
|
21
|
-
);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"conversations":[{"parameters":{"model":"dxn:com.anthropic.model.claudeOpus48","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"type":"object","required":["posts"],"properties":{"posts":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"A Universally Unique Lexicographically Sortable Identifier","pattern":"^[0-7][0-9A-HJKMNP-TV-Z]{25}$"},"snippet":{"type":"string"},"imageUrl":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].\n\n## Context Objects\n\n<object>\n <dxn>echo://BDJXMULPW5FB55UZ7KP5HLDHVTXUTHE2U/01JGFJJZ00G0WKQSJGMAKCNT8Y</dxn>\n <typename>org.dxos.type.magazine</typename>\n</object>","options":{}},{"role":"user","content":"You curate articles for a Magazine around the Topic described below.\n\nSelect only candidates that clearly match the Topic — quality over quantity.\n\nNever select duplicate articles. Two candidates are duplicates if they share a link or guid, or if\ntheir titles and content describe the same story (e.g. the same article syndicated by different\nfeeds). Keep only one of each — prefer the most complete or authoritative source — and skip the rest.\n\nFor each candidate you select, also produce:\n- A concise 1-2 sentence snippet (plain text, no markdown) capturing why the article is relevant to\n the Topic. If you read the full article, use it to write a richer snippet.\n- The best hero image URL for the article, when one is available.\n\n## Topic\n\nCurate articles about space exploration and astronomy — missions, spacecraft, telescopes, and astrophysics discoveries. Exclude unrelated business, finance, or software-tooling news.\n<input>{\"candidates\":[{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8S\",\"feedName\":\"Tech & Science Daily\",\"title\":\"NASA's Artemis II crew completes lunar flyby rehearsal\",\"description\":\"The four astronauts ran a full simulation of the crewed Moon flyby, practicing re-entry and recovery procedures ahead of next year’s launch.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/artemis-ii\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8T\",\"feedName\":\"Tech & Science Daily\",\"title\":\"James Webb telescope confirms the most distant galaxy yet seen\",\"description\":\"Astronomers used JWST spectroscopy to confirm a galaxy as it appeared 290 million years after the Big Bang, a new record for cosmic distance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/jwst-galaxy\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8V\",\"feedName\":\"Tech & Science Daily\",\"title\":\"Retail chain beats quarterly earnings estimates\",\"description\":\"Shares rose 6% after the company reported stronger-than-expected holiday sales and raised its full-year profit guidance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/retail-earnings\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8W\",\"feedName\":\"Tech & Science Daily\",\"title\":\"New JavaScript build tool promises 10x faster bundling\",\"description\":\"The Rust-based bundler aims to replace existing toolchains for large web applications with incremental compilation.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/js-bundler\"}]}</input>","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_018BJxwZmvRB27odbpJkTAJT","modelId":"claude-opus-4-8","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"Ep4CCmMIDxgCKkDm/fBnYSFnlyUV0jVq9erjrIGCuse0+3DF8kPQF+UBeai8XA2q2J5EBtP986g0KiIhmx/5vFCS1jg+BX1EieIjMg9jbGF1ZGUtb3B1cy00LTg4AEIIdGhpbmtpbmcSDDz59yO2FxmqNndO2RoMLZXt4K66QeYV6eA1IjBtN6fRt+H7MVf9Go+MSLyAzuLWUvYkVfpMpLmh8i8vIZ43Cch/Tiinjo4fOimUzi4qaT0YGuXzqoBxTDuokuelxGKlJRm1Y0HIggKXs1hHMi9FbSNTAtWDK+62jWddmqhy751D5L8g4KJZ6hAhgfmsN23Dhx6VvpHEsRYz7smUDcwloVb4fc60xgBv3SErvNHmNEBgG7ptwi98wxgB"}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"tool-params-start","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","name":"completeJob","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"{\"success","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"\":","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" {\"posts\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":":[{\"id\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":":\"01J","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"GFJJZ00G0WKQ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"SJGM","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"AKCNT","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"8S\",\"snippet","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"\":\"NA","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"SA's Artemi","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"s II astron","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"au","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ts ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"completed a","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" full reh","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"earsal of","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" their crewe","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"d l","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"unar ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"flyb","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"y, practicin","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"g re","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"-entry","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" and recove","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ry a","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"head of","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" next ye","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ar","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"'s lau","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"nch — a k","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ey milesto","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ne ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"for h","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"uman","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" deep-spac","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"e explor","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ation.\"},{\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"id","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"\":\"0","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"1JGF","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"JJZ00G","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"0WKQSJGMAKCN","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"T8T\",\"sni","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ppet\":\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"Using J","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"WST spectro","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"scopy, ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"as","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"tronom","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ers","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" confirme","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"d the most ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"di","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"stant galaxy","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" yet obs","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"erve","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"d, se","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"en ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"just 290 mi","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ll","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"io","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"n years a","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"fter t","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"he","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" Big Bang —","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" a r","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ecord-sett","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"in","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"g astr","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"oph","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ysic","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"s discov","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"ery","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":" abou","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"t the ea","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"rly ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"univ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","delta":"erse.\"}]}}","metadata":{}},{"type":"tool-params-end","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":2,"outputTokens":307,"totalTokens":309},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":1802},"cache_creation_input_tokens":1802,"cache_read_input_tokens":0,"input_tokens":2,"output_tokens":3,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"dxn:com.anthropic.model.claudeOpus48","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"type":"object","required":["posts"],"properties":{"posts":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"A Universally Unique Lexicographically Sortable Identifier","pattern":"^[0-7][0-9A-HJKMNP-TV-Z]{25}$"},"snippet":{"type":"string"},"imageUrl":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].\n\n## Context Objects\n\n<object>\n <dxn>echo://BDJXMULPW5FB55UZ7KP5HLDHVTXUTHE2U/01JGFJJZ00G0WKQSJGMAKCNT8Y</dxn>\n <typename>org.dxos.type.magazine</typename>\n</object>","options":{}},{"role":"user","content":"You curate articles for a Magazine around the Topic described below.\n\nSelect only candidates that clearly match the Topic — quality over quantity.\n\nNever select duplicate articles. Two candidates are duplicates if they share a link or guid, or if\ntheir titles and content describe the same story (e.g. the same article syndicated by different\nfeeds). Keep only one of each — prefer the most complete or authoritative source — and skip the rest.\n\nFor each candidate you select, also produce:\n- A concise 1-2 sentence snippet (plain text, no markdown) capturing why the article is relevant to\n the Topic. If you read the full article, use it to write a richer snippet.\n- The best hero image URL for the article, when one is available.\n\n## Topic\n\nCurate articles about space exploration and astronomy — missions, spacecraft, telescopes, and astrophysics discoveries. Exclude unrelated business, finance, or software-tooling news.\n<input>{\"candidates\":[{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8S\",\"feedName\":\"Tech & Science Daily\",\"title\":\"NASA's Artemis II crew completes lunar flyby rehearsal\",\"description\":\"The four astronauts ran a full simulation of the crewed Moon flyby, practicing re-entry and recovery procedures ahead of next year’s launch.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/artemis-ii\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8T\",\"feedName\":\"Tech & Science Daily\",\"title\":\"James Webb telescope confirms the most distant galaxy yet seen\",\"description\":\"Astronomers used JWST spectroscopy to confirm a galaxy as it appeared 290 million years after the Big Bang, a new record for cosmic distance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/jwst-galaxy\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8V\",\"feedName\":\"Tech & Science Daily\",\"title\":\"Retail chain beats quarterly earnings estimates\",\"description\":\"Shares rose 6% after the company reported stronger-than-expected holiday sales and raised its full-year profit guidance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/retail-earnings\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8W\",\"feedName\":\"Tech & Science Daily\",\"title\":\"New JavaScript build tool promises 10x faster bundling\",\"description\":\"The Rust-based bundler aims to replace existing toolchains for large web applications with incremental compilation.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/js-bundler\"}]}</input>","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"","options":{}},{"type":"tool-call","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","name":"completeJob","params":{"success":{"posts":[{"id":"01JGFJJZ00G0WKQSJGMAKCNT8S","snippet":"NASA's Artemis II astronauts completed a full rehearsal of their crewed lunar flyby, practicing re-entry and recovery ahead of next year's launch — a key milestone for human deep-space exploration."},{"id":"01JGFJJZ00G0WKQSJGMAKCNT8T","snippet":"Using JWST spectroscopy, astronomers confirmed the most distant galaxy yet observed, seen just 290 million years after the Big Bang — a record-setting astrophysics discovery about the early universe."}]}},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01K9YeiKJdB6VR2oKNriuew8","name":"completeJob","isFailure":false,"result":{},"providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01JDwb8qUNsKJvJ475DnpCou","modelId":"claude-opus-4-8","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I","metadata":{}},{"type":"text-delta","id":"0","delta":" curated the magazine, selecting the two articles that clearly match the space exploration and astronomy topic:\n\n1. **NASA's Artemis II","metadata":{}},{"type":"text-delta","id":"0","delta":" crew lunar flyby rehearsal** — a crewed Moon mission milestone.\n2. **James Webb telescope confirms most distant galaxy** — an astrophysics","metadata":{}},{"type":"text-delta","id":"0","delta":"/telescope discovery.\n\nI excluded the retail earnings article (business/finance) and the JavaScript build tool article (software t","metadata":{}},{"type":"text-delta","id":"0","delta":"ooling), both unrelated to the topic. No duplicates were present.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":2,"outputTokens":166,"totalTokens":168},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":285},"cache_creation_input_tokens":285,"cache_read_input_tokens":1802,"input_tokens":2,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"dxn:com.anthropic.model.claude-opus-4-8.default","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"type":"object","required":["posts"],"properties":{"posts":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"A Universally Unique Lexicographically Sortable Identifier","pattern":"^[0-7][0-9A-HJKMNP-TV-Z]{25}$"},"snippet":{"type":"string"},"imageUrl":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].\n\n## Context Objects\n\n<object>\n <dxn>echo://BDJXMULPW5FB55UZ7KP5HLDHVTXUTHE2U/01JGFJJZ00G0WKQSJGMAKCNT8Y</dxn>\n <typename>org.dxos.type.magazine</typename>\n</object>","options":{}},{"role":"user","content":"You curate articles for a Magazine around the Topic described below.\n\nSelect only candidates that clearly match the Topic — quality over quantity.\n\nNever select duplicate articles. Two candidates are duplicates if they share a link or guid, or if\ntheir titles and content describe the same story (e.g. the same article syndicated by different\nfeeds). Keep only one of each — prefer the most complete or authoritative source — and skip the rest.\n\nFor each candidate you select, also produce:\n- A concise 1-2 sentence snippet (plain text, no markdown) capturing why the article is relevant to\n the Topic. If you read the full article, use it to write a richer snippet.\n- The best hero image URL for the article, when one is available.\n\n## Topic\n\nCurate articles about space exploration and astronomy — missions, spacecraft, telescopes, and astrophysics discoveries. Exclude unrelated business, finance, or software-tooling news.\n<input>{\"candidates\":[{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8S\",\"feedName\":\"Tech & Science Daily\",\"title\":\"NASA's Artemis II crew completes lunar flyby rehearsal\",\"description\":\"The four astronauts ran a full simulation of the crewed Moon flyby, practicing re-entry and recovery procedures ahead of next year’s launch.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/artemis-ii\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8T\",\"feedName\":\"Tech & Science Daily\",\"title\":\"James Webb telescope confirms the most distant galaxy yet seen\",\"description\":\"Astronomers used JWST spectroscopy to confirm a galaxy as it appeared 290 million years after the Big Bang, a new record for cosmic distance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/jwst-galaxy\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8V\",\"feedName\":\"Tech & Science Daily\",\"title\":\"Retail chain beats quarterly earnings estimates\",\"description\":\"Shares rose 6% after the company reported stronger-than-expected holiday sales and raised its full-year profit guidance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/retail-earnings\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8W\",\"feedName\":\"Tech & Science Daily\",\"title\":\"New JavaScript build tool promises 10x faster bundling\",\"description\":\"The Rust-based bundler aims to replace existing toolchains for large web applications with incremental compilation.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/js-bundler\"}]}</input>","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01AoDKaEdrNQBSc8pmh1QJCW","modelId":"claude-opus-4-8","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EsQCCmMIDxgCKkCLSAgQ6d96to62hjcLm5D+fImzk2XZx6S4F2nFwdYmaR8JoMV3scGhT/ggac0/kcNf4+oUOahFviFW4hJF2NO7Mg9jbGF1ZGUtb3B1cy00LTg4AEIIdGhpbmtpbmcSDAdyGC9OmtOekGN4zRoMWhh5Vn2Kf3kcmtgkIjBr5JndmIsjLYmiRnoQWJkUsQOD9Y+yqcgwOTRPx1oB9Oyr2+1gfMA9wBYzcrIYZo4qjgGpbp/TzU3Q5i6VqE1QKctvDGB7D+cAkGSfeq3KBnKgQpCMJpGNQMEjD+Zuh4C/HLsFReE/w0fX1zMK1EUB9E+v9zIyPNz6lVK7cQM6CE3174CbZ5XNFBGpFCwrqY8EYdp2pxjyrv1f+Dqy31y49qVZi6QsDsogaFHFAot4hBHHSspnpAHqDRVgEQFP01y3GAE="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"tool-params-start","id":"toolu_019iL51MUHjw3twiR8rGmuCs","name":"completeJob","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"{\"success\": ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"{\"posts\":","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"[{\"id\":\"01JG","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"FJJZ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"00G0WK","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"QSJ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"GM","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"AKCNT8S\",\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"snippet\":","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"\"NA","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"SA's Art","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"emis","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" II ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"crew rehea","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"rsed thei","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"r crewed Moo","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"n ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"flyby, pra","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ct","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"icing ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"re-entry and","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" re","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"co","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"very ahea","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"d of n","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ext ye","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ar's la","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"unch —","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" a key mi","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"lestone","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" in retur","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ning human","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"s to l","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"un","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ar space.\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":",\"imageUr","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"l\":\"\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"},{","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"\"id\":\"01JGFJ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"JZ00G0WKQSJ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"GMAKCNT8","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"T\",\"s","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"nippet\":\"","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"Usin","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"g ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"JWS","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"T spectr","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"oscopy, ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"astro","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"nomers c","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"onfirmed","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" the most d","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"istant galax","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"y yet ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"obse","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"rved, ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"seen j","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ust ","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"29","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"0 million","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" years","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" afte","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"r the Big","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" Bang","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":", setting a","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":" ne","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"w c","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"osmic dist","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"ance record.","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"\",\"imageUrl","metadata":{}},{"type":"tool-params-delta","id":"toolu_019iL51MUHjw3twiR8rGmuCs","delta":"\":\"\"}]}}","metadata":{}},{"type":"tool-params-end","id":"toolu_019iL51MUHjw3twiR8rGmuCs","metadata":{}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":2,"outputTokens":331,"totalTokens":333},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":1802},"cache_creation_input_tokens":1802,"cache_read_input_tokens":0,"input_tokens":2,"output_tokens":6,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"dxn:com.anthropic.model.claude-opus-4-8.default","stream":true,"tools":[{"name":"completeJob","inputSchema":{"type":"object","required":[],"properties":{"success":{"type":"object","required":["posts"],"properties":{"posts":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"A Universally Unique Lexicographically Sortable Identifier","pattern":"^[0-7][0-9A-HJKMNP-TV-Z]{25}$"},"snippet":{"type":"string"},"imageUrl":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"failure":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Short message describing the error."},"description":{"type":"string","description":"Optional longer message describing in detail what went wrong"}},"additionalProperties":false}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"system","content":"You are an agent running in the non-interactive mode.\nThe user is unable to see what you are doing, and cannot answer any questions.\nDo not ask questions.\nComplete the task before you, and at the end call [completeJob] with the output.\nIf you are unable to complete the task, call [completeJob] with the failure reason.\nIf no output is required, call [completeJob] with an empty object: {}\nDo not stop until you call [completeJob].\n\n## Context Objects\n\n<object>\n <dxn>echo://BDJXMULPW5FB55UZ7KP5HLDHVTXUTHE2U/01JGFJJZ00G0WKQSJGMAKCNT8Y</dxn>\n <typename>org.dxos.type.magazine</typename>\n</object>","options":{}},{"role":"user","content":"You curate articles for a Magazine around the Topic described below.\n\nSelect only candidates that clearly match the Topic — quality over quantity.\n\nNever select duplicate articles. Two candidates are duplicates if they share a link or guid, or if\ntheir titles and content describe the same story (e.g. the same article syndicated by different\nfeeds). Keep only one of each — prefer the most complete or authoritative source — and skip the rest.\n\nFor each candidate you select, also produce:\n- A concise 1-2 sentence snippet (plain text, no markdown) capturing why the article is relevant to\n the Topic. If you read the full article, use it to write a richer snippet.\n- The best hero image URL for the article, when one is available.\n\n## Topic\n\nCurate articles about space exploration and astronomy — missions, spacecraft, telescopes, and astrophysics discoveries. Exclude unrelated business, finance, or software-tooling news.\n<input>{\"candidates\":[{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8S\",\"feedName\":\"Tech & Science Daily\",\"title\":\"NASA's Artemis II crew completes lunar flyby rehearsal\",\"description\":\"The four astronauts ran a full simulation of the crewed Moon flyby, practicing re-entry and recovery procedures ahead of next year’s launch.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/artemis-ii\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8T\",\"feedName\":\"Tech & Science Daily\",\"title\":\"James Webb telescope confirms the most distant galaxy yet seen\",\"description\":\"Astronomers used JWST spectroscopy to confirm a galaxy as it appeared 290 million years after the Big Bang, a new record for cosmic distance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/jwst-galaxy\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8V\",\"feedName\":\"Tech & Science Daily\",\"title\":\"Retail chain beats quarterly earnings estimates\",\"description\":\"Shares rose 6% after the company reported stronger-than-expected holiday sales and raised its full-year profit guidance.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/retail-earnings\"},{\"id\":\"01JGFJJZ00G0WKQSJGMAKCNT8W\",\"feedName\":\"Tech & Science Daily\",\"title\":\"New JavaScript build tool promises 10x faster bundling\",\"description\":\"The Rust-based bundler aims to replace existing toolchains for large web applications with incremental compilation.\",\"published\":\"2026-05-01T00:00:00Z\",\"link\":\"https://example.com/js-bundler\"}]}</input>","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"","options":{}},{"type":"tool-call","id":"toolu_019iL51MUHjw3twiR8rGmuCs","name":"completeJob","params":{"success":{"posts":[{"id":"01JGFJJZ00G0WKQSJGMAKCNT8S","snippet":"NASA's Artemis II crew rehearsed their crewed Moon flyby, practicing re-entry and recovery ahead of next year's launch — a key milestone in returning humans to lunar space.","imageUrl":""},{"id":"01JGFJJZ00G0WKQSJGMAKCNT8T","snippet":"Using JWST spectroscopy, astronomers confirmed the most distant galaxy yet observed, seen just 290 million years after the Big Bang, setting a new cosmic distance record.","imageUrl":""}]}},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_019iL51MUHjw3twiR8rGmuCs","name":"completeJob","isFailure":false,"result":{},"providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01E5uUhLRugSS4T7vP2VJX6v","modelId":"claude-opus-4-8","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"I","metadata":{}},{"type":"text-delta","id":"0","delta":" curated the magazine successfully. From the four candidates, I selected the two that clearly match the space exploration and","metadata":{}},{"type":"text-delta","id":"0","delta":" astronomy topic:\n\n1. **NASA's Artemis II crew completes lunar flyby rehearsal** — a space mission story about retur","metadata":{}},{"type":"text-delta","id":"0","delta":"ning humans to lunar space.\n2. **James Webb telescope confirms the most distant galaxy yet seen** — an astrophysics discovery using a telescope.\n\nI excluded the ret","metadata":{}},{"type":"text-delta","id":"0","delta":"ail earnings article (business/finance) and the JavaScript build tool article (software tooling), as both fall outside the topic. No duplicates were present.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":2,"outputTokens":185,"totalTokens":187},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":288},"cache_creation_input_tokens":288,"cache_read_input_tokens":1802,"input_tokens":2,"output_tokens":1,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
// Run in the node environment (not the package-default happy-dom): the agent's outbound Anthropic
|
|
6
|
-
// call goes through real `fetch`; happy-dom's fetch enforces CORS and blocks the cross-origin request.
|
|
7
|
-
// extractArticle falls back to defuddle/node (linkedom) when DOMParser is absent, so the real
|
|
8
|
-
// fetchArticleContent tool works here without a DOM polyfill.
|
|
9
|
-
// @vitest-environment node
|
|
10
|
-
|
|
11
|
-
import { describe, it } from '@effect/vitest';
|
|
12
|
-
import * as Effect from 'effect/Effect';
|
|
13
|
-
import { afterEach, beforeEach, vi } from 'vitest';
|
|
14
|
-
|
|
15
|
-
import { AgentHandlers } from '@dxos/assistant-toolkit';
|
|
16
|
-
import { Operation } from '@dxos/compute';
|
|
17
|
-
import { Database, Feed, Obj, Ref, Tag } from '@dxos/echo';
|
|
18
|
-
import { TestHelpers } from '@dxos/effect/testing';
|
|
19
|
-
import { AssistantTestLayer } from '@dxos/functions-runtime/testing';
|
|
20
|
-
import { EntityId } from '@dxos/keys';
|
|
21
|
-
import { StateMap, TagIndex, Text } from '@dxos/schema';
|
|
22
|
-
|
|
23
|
-
import { MagazineSkill } from '../skills';
|
|
24
|
-
import { FeedOperation, Magazine, Subscription } from '../types';
|
|
25
|
-
import { MagazineOperationHandlerSet } from './index';
|
|
26
|
-
|
|
27
|
-
EntityId.dangerouslyDisableRandomness();
|
|
28
|
-
|
|
29
|
-
const TestLayer = AssistantTestLayer({
|
|
30
|
-
// MagazineOperationHandlerSet provides CurateMagazine + SyncFeed + FetchArticleContent (the skill
|
|
31
|
-
// tool); AgentHandlers provides the RunInstructions handler the curate operation invokes.
|
|
32
|
-
operationHandlers: [MagazineOperationHandlerSet, AgentHandlers],
|
|
33
|
-
types: [
|
|
34
|
-
Feed.Feed,
|
|
35
|
-
Subscription.Subscription,
|
|
36
|
-
Subscription.Post,
|
|
37
|
-
Magazine.Magazine,
|
|
38
|
-
Tag.Tag,
|
|
39
|
-
Text.Text,
|
|
40
|
-
StateMap.StateMap,
|
|
41
|
-
TagIndex.TagIndex,
|
|
42
|
-
],
|
|
43
|
-
skills: [MagazineSkill.make()],
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Candidate posts seeded into the subscription's backing queue: two clearly on-topic for a
|
|
48
|
-
* space/astronomy magazine, two clearly off-topic.
|
|
49
|
-
*/
|
|
50
|
-
const CANDIDATES = [
|
|
51
|
-
{
|
|
52
|
-
guid: 'artemis-ii',
|
|
53
|
-
title: "NASA's Artemis II crew completes lunar flyby rehearsal",
|
|
54
|
-
description:
|
|
55
|
-
'The four astronauts ran a full simulation of the crewed Moon flyby, practicing re-entry and recovery procedures ahead of next year’s launch.',
|
|
56
|
-
onTopic: true,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
guid: 'jwst-galaxy',
|
|
60
|
-
title: 'James Webb telescope confirms the most distant galaxy yet seen',
|
|
61
|
-
description:
|
|
62
|
-
'Astronomers used JWST spectroscopy to confirm a galaxy as it appeared 290 million years after the Big Bang, a new record for cosmic distance.',
|
|
63
|
-
onTopic: true,
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
guid: 'retail-earnings',
|
|
67
|
-
title: 'Retail chain beats quarterly earnings estimates',
|
|
68
|
-
description:
|
|
69
|
-
'Shares rose 6% after the company reported stronger-than-expected holiday sales and raised its full-year profit guidance.',
|
|
70
|
-
onTopic: false,
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
guid: 'js-bundler',
|
|
74
|
-
title: 'New JavaScript build tool promises 10x faster bundling',
|
|
75
|
-
description:
|
|
76
|
-
'The Rust-based bundler aims to replace existing toolchains for large web applications with incremental compilation.',
|
|
77
|
-
onTopic: false,
|
|
78
|
-
},
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
/** Minimal article page so the real extractArticle (defuddle) has a body to parse. */
|
|
82
|
-
const articleHtml = (title: string, body: string) =>
|
|
83
|
-
`<!doctype html><html><head><title>${title}</title></head><body><article><h1>${title}</h1><p>${body}</p></article></body></html>`;
|
|
84
|
-
|
|
85
|
-
// Preserve the real fetch so the stub can pass the agent's Anthropic call through (replay is
|
|
86
|
-
// memoized, so no real call is made then; generation uses the live API key).
|
|
87
|
-
// eslint-disable-next-line no-restricted-globals
|
|
88
|
-
const realFetch = globalThis.fetch.bind(globalThis);
|
|
89
|
-
|
|
90
|
-
describe('CurateMagazine (LLM)', () => {
|
|
91
|
-
// Stub only the network boundary: serve canned HTML for the candidate article URLs (so the real
|
|
92
|
-
// fetchArticleContent tool runs deterministically), and pass everything else (Anthropic) through.
|
|
93
|
-
beforeEach(() => {
|
|
94
|
-
vi.stubGlobal(
|
|
95
|
-
'fetch',
|
|
96
|
-
vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
97
|
-
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
|
98
|
-
const candidate = CANDIDATES.find((entry) => url.includes(entry.guid));
|
|
99
|
-
if (candidate) {
|
|
100
|
-
return new Response(articleHtml(candidate.title, candidate.description), {
|
|
101
|
-
status: 200,
|
|
102
|
-
headers: { 'content-type': 'text/html' },
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
return realFetch(input, init);
|
|
106
|
-
}),
|
|
107
|
-
);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
afterEach(() => {
|
|
111
|
-
vi.unstubAllGlobals();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it.effect(
|
|
115
|
-
'selects only the posts matching the magazine topic',
|
|
116
|
-
Effect.fnUntraced(
|
|
117
|
-
function* ({ expect }) {
|
|
118
|
-
// Subscription with no `url` → the SyncFeed phase is skipped (no network); curation reads the
|
|
119
|
-
// posts we seed directly into the backing queue below.
|
|
120
|
-
const subscription = yield* Database.add(
|
|
121
|
-
Subscription.makeSubscription({ name: 'Tech & Science Daily', type: 'rss' }),
|
|
122
|
-
);
|
|
123
|
-
yield* Database.flush();
|
|
124
|
-
|
|
125
|
-
const postFeed = yield* Database.load(subscription.feed);
|
|
126
|
-
const posts = CANDIDATES.map((candidate) =>
|
|
127
|
-
Obj.make(Subscription.Post, {
|
|
128
|
-
title: candidate.title,
|
|
129
|
-
description: candidate.description,
|
|
130
|
-
link: `https://example.com/${candidate.guid}`,
|
|
131
|
-
guid: candidate.guid,
|
|
132
|
-
published: '2026-05-01T00:00:00Z',
|
|
133
|
-
source: Ref.make(subscription),
|
|
134
|
-
}),
|
|
135
|
-
);
|
|
136
|
-
yield* Feed.append(postFeed, posts);
|
|
137
|
-
yield* Database.flush();
|
|
138
|
-
|
|
139
|
-
const magazine = yield* Database.add(
|
|
140
|
-
Magazine.make({
|
|
141
|
-
name: 'The Cosmos',
|
|
142
|
-
feeds: [Ref.make(subscription)],
|
|
143
|
-
instructions:
|
|
144
|
-
'Curate articles about space exploration and astronomy — missions, spacecraft, telescopes, and astrophysics discoveries. Exclude unrelated business, finance, or software-tooling news.',
|
|
145
|
-
}),
|
|
146
|
-
);
|
|
147
|
-
yield* Database.flush();
|
|
148
|
-
|
|
149
|
-
const result = yield* Operation.invoke(FeedOperation.CurateMagazine, { magazine: Ref.make(magazine) });
|
|
150
|
-
|
|
151
|
-
// Load the curated post refs to read their titles (`ref.target` is not hydrated synchronously).
|
|
152
|
-
const curatedPosts = yield* Effect.promise(() => Promise.all(magazine.posts.map((ref) => ref.load())));
|
|
153
|
-
const curatedTitles = curatedPosts.map((post) => post.title);
|
|
154
|
-
|
|
155
|
-
// The two space/astronomy posts are curated; the business + tooling posts are not.
|
|
156
|
-
expect(curatedTitles).toContain(CANDIDATES[0].title);
|
|
157
|
-
expect(curatedTitles).toContain(CANDIDATES[1].title);
|
|
158
|
-
expect(curatedTitles).not.toContain(CANDIDATES[2].title);
|
|
159
|
-
expect(curatedTitles).not.toContain(CANDIDATES[3].title);
|
|
160
|
-
expect(result.curated).toBe(2);
|
|
161
|
-
},
|
|
162
|
-
Effect.provide(TestLayer),
|
|
163
|
-
TestHelpers.provideTestContext,
|
|
164
|
-
),
|
|
165
|
-
{ timeout: 240_000 },
|
|
166
|
-
);
|
|
167
|
-
});
|