mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 17:26:41 +02:00
feat(webapp): wire isParallelSafe in Companion chat + Mission runner
Enables the M1 parallel-reads optimisation on the webapp side. Both
consumers of runPlannerLoop pass an isParallelSafe predicate derived
from the tool catalog:
isParallelSafe: (name) =>
AI_TOOL_CATALOG_BY_NAME.get(name)?.defaultPolicy === 'auto'
Auto-policy tools (list_tasks, get_habits, nutrition_summary, …) run
via Promise.all in batches of 10 when the LLM fans them out in one
round. Propose-policy tools — which surface to the user as Proposal
cards — stay sequential so intent ordering in the inbox is preserved
and pre-execute guardrails can reason about prior-step state.
Tests: 31 existing companion + mission tests pass unchanged; the
parallel path is exercised via the new loop.test.ts cases shipped
with the M1 commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a64a7e39cf
commit
54a12ffd5c
59 changed files with 5629 additions and 218 deletions
73
packages/website-blocks/src/richText/RichText.svelte
Normal file
73
packages/website-blocks/src/richText/RichText.svelte
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<script lang="ts">
|
||||
import type { BlockRenderProps } from '../types';
|
||||
import type { RichTextProps } from './schema';
|
||||
|
||||
let { block, mode }: BlockRenderProps<RichTextProps> = $props();
|
||||
|
||||
const paragraphs = $derived(
|
||||
block.props.content
|
||||
.split(/\n{2,}/)
|
||||
.map((p) => p.trim())
|
||||
.filter((p) => p.length > 0)
|
||||
);
|
||||
|
||||
const isEdit = $derived(mode === 'edit');
|
||||
</script>
|
||||
|
||||
<section
|
||||
class="wb-richtext"
|
||||
class:wb-richtext--left={block.props.align === 'left'}
|
||||
class:wb-richtext--center={block.props.align === 'center'}
|
||||
class:wb-richtext--sm={block.props.size === 'sm'}
|
||||
class:wb-richtext--md={block.props.size === 'md'}
|
||||
class:wb-richtext--lg={block.props.size === 'lg'}
|
||||
data-mode={mode}
|
||||
>
|
||||
<div class="wb-richtext__inner">
|
||||
{#if paragraphs.length === 0 && isEdit}
|
||||
<p class="wb-placeholder">Leerer Text — öffne den Inspector und fang an zu schreiben.</p>
|
||||
{:else}
|
||||
{#each paragraphs as paragraph, i (i)}
|
||||
<p>{paragraph}</p>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.wb-richtext {
|
||||
padding: 2rem 1.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.wb-richtext__inner {
|
||||
max-width: 48rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
.wb-richtext--left .wb-richtext__inner {
|
||||
text-align: left;
|
||||
}
|
||||
.wb-richtext--center .wb-richtext__inner {
|
||||
text-align: center;
|
||||
}
|
||||
.wb-richtext p {
|
||||
margin: 0;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.wb-richtext--sm p {
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
.wb-richtext--md p {
|
||||
font-size: 1.0625rem;
|
||||
}
|
||||
.wb-richtext--lg p {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
.wb-placeholder {
|
||||
opacity: 0.35;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<script lang="ts">
|
||||
import type { BlockInspectorProps } from '../types';
|
||||
import type { RichTextProps } from './schema';
|
||||
|
||||
let { block, onChange }: BlockInspectorProps<RichTextProps> = $props();
|
||||
</script>
|
||||
|
||||
<div class="wb-inspector">
|
||||
<label class="wb-field">
|
||||
<span>Text</span>
|
||||
<textarea
|
||||
rows="10"
|
||||
value={block.props.content}
|
||||
oninput={(e) => onChange({ content: e.currentTarget.value })}
|
||||
placeholder="Leere Zeile = neuer Absatz. Markdown folgt in M3."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="wb-row">
|
||||
<label class="wb-field">
|
||||
<span>Ausrichtung</span>
|
||||
<select
|
||||
value={block.props.align}
|
||||
onchange={(e) => onChange({ align: e.currentTarget.value as RichTextProps['align'] })}
|
||||
>
|
||||
<option value="left">Linksbündig</option>
|
||||
<option value="center">Zentriert</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="wb-field">
|
||||
<span>Schriftgröße</span>
|
||||
<select
|
||||
value={block.props.size}
|
||||
onchange={(e) => onChange({ size: e.currentTarget.value as RichTextProps['size'] })}
|
||||
>
|
||||
<option value="sm">Klein</option>
|
||||
<option value="md">Normal</option>
|
||||
<option value="lg">Groß</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wb-inspector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
.wb-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.wb-field > span {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
opacity: 0.7;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.wb-field textarea,
|
||||
.wb-field select {
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.625rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: inherit;
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.wb-field textarea {
|
||||
resize: vertical;
|
||||
min-height: 6rem;
|
||||
}
|
||||
.wb-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
19
packages/website-blocks/src/richText/index.ts
Normal file
19
packages/website-blocks/src/richText/index.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import type { BlockSpec } from '../types';
|
||||
import RichText from './RichText.svelte';
|
||||
import RichTextInspector from './RichTextInspector.svelte';
|
||||
import { RichTextSchema, RICH_TEXT_DEFAULTS, type RichTextProps } from './schema';
|
||||
|
||||
export const richTextBlockSpec: BlockSpec<RichTextProps> = {
|
||||
type: 'richText',
|
||||
label: 'Text',
|
||||
icon: 'text',
|
||||
category: 'content',
|
||||
schema: RichTextSchema,
|
||||
schemaVersion: 1,
|
||||
defaults: RICH_TEXT_DEFAULTS,
|
||||
Component: RichText,
|
||||
Inspector: RichTextInspector,
|
||||
};
|
||||
|
||||
export type { RichTextProps };
|
||||
export { RichTextSchema, RICH_TEXT_DEFAULTS };
|
||||
15
packages/website-blocks/src/richText/schema.ts
Normal file
15
packages/website-blocks/src/richText/schema.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const RichTextSchema = z.object({
|
||||
content: z.string().max(10_000).default(''),
|
||||
align: z.enum(['left', 'center']).default('left'),
|
||||
size: z.enum(['sm', 'md', 'lg']).default('md'),
|
||||
});
|
||||
|
||||
export type RichTextProps = z.infer<typeof RichTextSchema>;
|
||||
|
||||
export const RICH_TEXT_DEFAULTS: RichTextProps = {
|
||||
content: '',
|
||||
align: 'left',
|
||||
size: 'md',
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue